<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.open-xchange.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dominik.epple</id>
	<title>Open-Xchange - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.open-xchange.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dominik.epple"/>
	<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Special:Contributions/Dominik.epple"/>
	<updated>2026-06-30T23:01:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=My.cnf&amp;diff=24541</id>
		<title>My.cnf</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=My.cnf&amp;diff=24541"/>
		<updated>2019-02-14T14:45:12Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Functional items */ Fix typo.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page lists some performance tuning parameters which we recommend for tuning MySQL database services used for Open-Xchange installations.&lt;br /&gt;
&lt;br /&gt;
We cannot guarantee this is an exhaustive list of required settings. So treat this list of tunings as probably required, but not necessarily sufficient settings for optimal MySQL performance.&lt;br /&gt;
&lt;br /&gt;
Furthermore, as MySQL changes over time, settings which have been correct as of the time of writing may become incorrect later.&lt;br /&gt;
&lt;br /&gt;
However, this list of settings is the result of internal performance testing and real world customer feedback, so it should be valid to some extent.&lt;br /&gt;
&lt;br /&gt;
In the end, proper configuration of the database service for performance, but also consistency, durability and high availability is in the responsibility of the customer.&lt;br /&gt;
&lt;br /&gt;
=== Performance items ===&lt;br /&gt;
&lt;br /&gt;
* You should adjust the &amp;lt;code&amp;gt;innodb_buffer_pool_size&amp;lt;/code&amp;gt; parameter for reasonable memory usage. Our DB sizing is mainly memory-driven and this is where most of the memory goes. Our standard DB machine sizing assumption is 32 GB if MySQL dedicated memory on a 48 GB total memory machine. On such a machine, you would configure 32 GB for the innodb_buffer_pool size, being aware that MySQL does also require memory for other things, in particular there are some also per-connection related memory spendings, which can become substantial if you allow for a lot of maximum concurrent connections. Please watch your memory configuration carefully, use monitoring and tools like mysqltuner.pl.&lt;br /&gt;
&lt;br /&gt;
* On bigger installations you should use &amp;lt;code&amp;gt;innodb_file_per_table = 1&amp;lt;/code&amp;gt;, which is creating single files instead of one big blob. If you change this parameter after the database initialization you have to recreate (like dump/drop and re-import) the tables.&lt;br /&gt;
&lt;br /&gt;
* It can help to put different parts of the mysql datadir (iblog, ibdata) on different filesystems / storage devices. This depends on your infrastructure. Settings herefore are &amp;lt;code&amp;gt;datadir&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;innodb_data_home_dir&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;innodb_log_group_home_dir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* If your storage is fast (handle a lot of IOPS), you may want to adjust the &amp;lt;code&amp;gt;innodb_io_capacity&amp;lt;/code&amp;gt; setting, which defines a limit for the IOPS MySQL will create. The default is 200, which is sensible for single spindle disks. But if you have storage appliances with a lot of fast SAS drives, or even SSDs, this limit can be increased greatly.&lt;br /&gt;
&lt;br /&gt;
=== Functional items ===&lt;br /&gt;
&lt;br /&gt;
* Query cache is to be switched off; as we found in our own benchmarks and as backed up by upstreams, this hurts performance in load situations with high concurrency. [https://dev.mysql.com/doc/refman/5.7/en/query-cache.htm The query cache is deprecated as of MySQL 5.7.20, and is removed in MySQL 8.0], so we recommend also to switch that off.&lt;br /&gt;
* Starting with App Suite 7.10.0, &amp;lt;code&amp;gt;character_set_server&amp;lt;/code&amp;gt; must be set to &amp;lt;code&amp;gt;utf8mb4&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;collation_server&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;utf8mb4_general_ci&amp;lt;/code&amp;gt;. For older versions it must be &amp;lt;code&amp;gt;utf8&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;utf8_general_ci&amp;lt;/code&amp;gt; respectively.&lt;br /&gt;
* Starting with MySQL 5.7 &amp;lt;code&amp;gt;innodb_strict_mode&amp;lt;/code&amp;gt; must be disabled.&lt;br /&gt;
* Starting with MySQL 5.6 and MariaDB 10.1 &amp;lt;code&amp;gt;sql_mode&amp;lt;/code&amp;gt; must be configured according to belows matrix.&lt;br /&gt;
&lt;br /&gt;
==== SQL mode matrix ====&lt;br /&gt;
&lt;br /&gt;
The default for the &amp;lt;code&amp;gt;sql_mode&amp;lt;/code&amp;gt; setting changes regularly with MariaDB and MySQL releases and is not even consistent anymore between the two derivates. SQL modes affect how data and queries are handled at runtime. Enabling strict modes might lead to errors in terms of failing queries or even update tasks. We strongly recommend the following configuration to avoid according runtime errors:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| sql_mode&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| App Suite 7.8.4&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| App Suite 7.10.0&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MySQL 5.6&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MySQL 5.7&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MariaDB 10.1&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MariaDB 10.2&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample config files ===&lt;br /&gt;
&lt;br /&gt;
For easy deployment we recommend not to edit existing the existing my.cnf file, rather assume the distro provides sane settings for most of the items and override items where needed.&lt;br /&gt;
&lt;br /&gt;
As in MySQL there is a [https://dev.mysql.com/doc/refman/5.7/en/option-files.html last instance wins] semantic in options file parsing, we propose to create a custom include directory &amp;quot;ox.conf.d&amp;quot;, put our custom config files therein, and include this directory as latest directory in /etc/mysql/my.cnf.&lt;br /&gt;
&lt;br /&gt;
To put in that directory, we have one main tuning file called tunings.cnf, one galera-related file if galera is in use, and one more galera host-specific file which contains per-host settings if using galera (separate in a file of its own for easier configuration management).&lt;br /&gt;
&lt;br /&gt;
So, start with adding to the existing my.cnf at the very bottom:&lt;br /&gt;
&lt;br /&gt;
 !includedir /etc/mysql/ox.conf.d/&lt;br /&gt;
&lt;br /&gt;
Create that directory and put in there the generic ox tunings file /etc/mysql/ox.conf.d/tunings.cnf:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 bind-address		 = *&lt;br /&gt;
 &lt;br /&gt;
 #innodb_use_native_aio = 0&lt;br /&gt;
 &lt;br /&gt;
 table_open_cache = 3072&lt;br /&gt;
 table_definition_cache = 4096&lt;br /&gt;
 max_heap_table_size = 64M&lt;br /&gt;
 tmp_table_size = 64M&lt;br /&gt;
 max_connections = 505&lt;br /&gt;
 max_user_connections = 500&lt;br /&gt;
 max_allowed_packet = 16M&lt;br /&gt;
 thread_cache_size = 32&lt;br /&gt;
 query_cache_size = 0&lt;br /&gt;
 query_cache_type = 0&lt;br /&gt;
 innodb_buffer_pool_size = 32G&lt;br /&gt;
 # the default value in MySQL 5.6.6 and higher is 8 when innodb_buffer_pool_size is greater than or equal to 1GB. Otherwise, the default is 1. &lt;br /&gt;
 innodb_buffer_pool_instances = 32&lt;br /&gt;
 innodb_data_file_path = ibdata1:128M:autoextend&lt;br /&gt;
 innodb_file_per_table = 1&lt;br /&gt;
 # innodb_log_file_size should be 25% of the innodb_buffer_pool_size&lt;br /&gt;
 innodb_log_file_size = 4GB&lt;br /&gt;
 # default and recommended value is 2&lt;br /&gt;
 innodb_log_files_in_group = 2&lt;br /&gt;
 # adjust according to your storage&lt;br /&gt;
 #innodb_io_capacity = 1000&lt;br /&gt;
 &lt;br /&gt;
 # we are unsure about this setting. Newer versions of MariaDB seem to be fine with low (=1) settings for this value.&lt;br /&gt;
 # Traditionally we encountered values up to 4x the number of cores.&lt;br /&gt;
 # Default seems to be number of cores, so let's stick the default&lt;br /&gt;
 # In the end, we need to leave this setting up to you: if you dont get full cpu utilization in cpu-bound situations, this might be a setting to increase.&lt;br /&gt;
 #thread_pool_size = 32&lt;br /&gt;
 &lt;br /&gt;
 binlog_cache_size = 1M&lt;br /&gt;
 sync_binlog = 8&lt;br /&gt;
 binlog_format = row&lt;br /&gt;
 &lt;br /&gt;
 character_set_server = utf8mb4&lt;br /&gt;
 collation_server = utf8mb4_general_ci&lt;br /&gt;
 &lt;br /&gt;
 # This was default_table_type previous to MySQL 5.5&lt;br /&gt;
 default_storage_engine = InnoDB&lt;br /&gt;
 &lt;br /&gt;
 innodb_autoinc_lock_mode = 2&lt;br /&gt;
 &lt;br /&gt;
 # keep until 5.6, deprecated later&lt;br /&gt;
 innodb_locks_unsafe_for_binlog = 1&lt;br /&gt;
 &lt;br /&gt;
 # we found this has huge impact on (galera) performance&lt;br /&gt;
 # default (consistent) setting of 1 greatly severs performance&lt;br /&gt;
 # in galera (or async master-slave) deployments, you might be ok with setting this to 0 or 2,&lt;br /&gt;
 # assuming our consistency / availability comes from replication / other cluster nodes&lt;br /&gt;
 innodb_flush_log_at_trx_commit = 0&lt;br /&gt;
 &lt;br /&gt;
 # for performance testing systems, to not use excessive disk space&lt;br /&gt;
 #expire_logs_days = 1&lt;br /&gt;
 &lt;br /&gt;
 # MySQL 5.7.7 has changed the default to 1. Disable it explicitly to prevent from errors based on invalid data stored by former App Suite or MySQL versions.&lt;br /&gt;
 innodb_strict_mode = 0&lt;br /&gt;
 &lt;br /&gt;
 # The following value refers to App Suite 7.10 on top of MySQL 5.7. For other combinations see the sql mode matrix at http://oxpedia.org/wiki/index.php?title=My.cnf.&lt;br /&gt;
 sql_mode = NO_ENGINE_SUBSTITUTION,NO_AUTO_CREATE_USER,ONLY_FULL_GROUP_BY&lt;br /&gt;
&lt;br /&gt;
If using galera, use the following galera configuration file &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/wsrep.cnf&amp;lt;/code&amp;gt;. See the comments in that file for values to be adjusted.&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 # adjust for your distros SO location&lt;br /&gt;
 wsrep_provider=/usr/lib/libgalera_smm.so&lt;br /&gt;
 &lt;br /&gt;
 # this is the big winner and enables us to switch off OX's replication monitor&lt;br /&gt;
 wsrep_sync_wait=1&lt;br /&gt;
 &lt;br /&gt;
 # pick a unique cluster name&lt;br /&gt;
 wsrep_cluster_name=devcluster&lt;br /&gt;
 # adjust for your IPs / hostnames&lt;br /&gt;
 wsrep_cluster_address=gcomm://10.20.29.68,10.20.29.69,10.20.29.70&lt;br /&gt;
 &lt;br /&gt;
 # put this in host.cnf&lt;br /&gt;
 #wsrep_node_name=...&lt;br /&gt;
 #wsrep_node_address=...&lt;br /&gt;
 &lt;br /&gt;
 # For some MariaDB versions, xtrabackup-v2 no longer works, instead use &amp;quot;mariabackup&amp;quot;&lt;br /&gt;
 # (needs to be installed separately, e.g. via the mariadb-backup-10.2 package)&lt;br /&gt;
 # see upstream documentation for details: &lt;br /&gt;
 # https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/#xtrabackup&lt;br /&gt;
 #&lt;br /&gt;
 # wsrep_sst_method=mariabackup&lt;br /&gt;
 wsrep_sst_method=xtrabackup-v2&lt;br /&gt;
&lt;br /&gt;
 # wsrep_sst_auth if of format username:password&lt;br /&gt;
 # pick whatever you configured on the donor node&lt;br /&gt;
 wsrep_sst_auth=sstuser:...&lt;br /&gt;
 &lt;br /&gt;
 # galera-specific tunings&lt;br /&gt;
 wsrep_slave_threads = 32&lt;br /&gt;
 &lt;br /&gt;
 # finally, enable wsrep: required for some MariaDB versions&lt;br /&gt;
 wsrep_on=ON -- Enable wsrep replication (MariaDB starting 10.1.1) &lt;br /&gt;
&lt;br /&gt;
Galera-related host-specific settings go in /etc/mysql/ox.conf.d/host.cnf:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 # the nodes hostname&lt;br /&gt;
 wsrep_node_name=...&lt;br /&gt;
 # and the IP of the wsrep relevant interface, if multiple&lt;br /&gt;
 wsrep_node_address=10.20.29.68&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24297</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24297"/>
		<updated>2018-09-27T14:25:22Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* First node (continued) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
That tool will ask for the current root password (which is empty by default) and subsequently questions like:&lt;br /&gt;
&lt;br /&gt;
 Change the root password? [Y/n]&lt;br /&gt;
 Remove anonymous users? [Y/n]&lt;br /&gt;
 Disallow root login remotely? [Y/n]&lt;br /&gt;
 Remove test database and access to it? [Y/n]&lt;br /&gt;
 Reload privilege tables now? [Y/n]&lt;br /&gt;
&lt;br /&gt;
You should answer all these questions with &amp;quot;yes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Configure a strong password for the MySQL &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; user.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 systemctl enable mysql.service&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1, 10.2&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1, 10.2&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1, 10.2&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1, 10.2: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # MariaDB 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Please use a real password.&lt;br /&gt;
* The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly.&lt;br /&gt;
* If using a database on the same host as the middlware (usually done for POCs and demo installations), you need to grant also to the ''localhost'' host.&lt;br /&gt;
* Consult [[AppSuite:DB_user_privileges]] (or ''grep GRANT /opt/open-xchange/sbin/initconfigdb'') for an up-to-date list of required privileges. The following statement was correct as of the time of writing this section.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24296</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24296"/>
		<updated>2018-09-27T14:24:56Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* First node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
That tool will ask for the current root password (which is empty by default) and subsequently questions like:&lt;br /&gt;
&lt;br /&gt;
 Change the root password? [Y/n]&lt;br /&gt;
 Remove anonymous users? [Y/n]&lt;br /&gt;
 Disallow root login remotely? [Y/n]&lt;br /&gt;
 Remove test database and access to it? [Y/n]&lt;br /&gt;
 Reload privilege tables now? [Y/n]&lt;br /&gt;
&lt;br /&gt;
You should answer all these questions with &amp;quot;yes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Configure a strong password for the MySQL &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; user.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 systemctl enable mysql.service&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1, 10.2&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1, 10.2&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1, 10.2&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # MariaDB 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Please use a real password.&lt;br /&gt;
* The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly.&lt;br /&gt;
* If using a database on the same host as the middlware (usually done for POCs and demo installations), you need to grant also to the ''localhost'' host.&lt;br /&gt;
* Consult [[AppSuite:DB_user_privileges]] (or ''grep GRANT /opt/open-xchange/sbin/initconfigdb'') for an up-to-date list of required privileges. The following statement was correct as of the time of writing this section.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=My.cnf&amp;diff=24295</id>
		<title>My.cnf</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=My.cnf&amp;diff=24295"/>
		<updated>2018-09-27T14:24:07Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Sample config files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page lists some performance tuning parameters which we recommend for tuning MySQL database services used for Open-Xchange installations.&lt;br /&gt;
&lt;br /&gt;
We cannot guarantee this is an exhaustive list of required settings. So treat this list of tunings as probably required, but not necessarily sufficient settings for optimal MySQL performance.&lt;br /&gt;
&lt;br /&gt;
Furthermore, as MySQL changes over time, settings which have been correct as of the time of writing may become incorrect later.&lt;br /&gt;
&lt;br /&gt;
However, this list of settings is the result of internal performance testing and real world customer feedback, so it should be valid to some extent.&lt;br /&gt;
&lt;br /&gt;
In the end, proper configuration of the database service for performance, but also consistency, durability and high availability is in the responsibility of the customer.&lt;br /&gt;
&lt;br /&gt;
=== Performance items ===&lt;br /&gt;
&lt;br /&gt;
* You should adjust the &amp;lt;code&amp;gt;innodb_buffer_pool_size&amp;lt;/code&amp;gt; parameter for reasonable memory usage. Our DB sizing is mainly memory-driven and this is where most of the memory goes. Our standard DB machine sizing assumption is 32 GB if MySQL dedicated memory on a 48 GB total memory machine. On such a machine, you would configure 32 GB for the innodb_buffer_pool size, being aware that MySQL does also require memory for other things, in particular there are some also per-connection related memory spendings, which can become substantial if you allow for a lot of maximum concurrent connections. Please watch your memory configuration carefully, use monitoring and tools like mysqltuner.pl.&lt;br /&gt;
&lt;br /&gt;
* On bigger installations you should use &amp;lt;code&amp;gt;innodb_file_per_table = 1&amp;lt;/code&amp;gt;, which is creating single files instead of one big blob. If you change this parameter after the database initialization you have to recreate (like dump/drop and re-import) the tables.&lt;br /&gt;
&lt;br /&gt;
* It can help to put different parts of the mysql datadir (iblog, ibdata) on different filesystems / storage devices. This depends on your infrastructure. Settings herefore are &amp;lt;code&amp;gt;datadir&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;innodb_data_home_dir&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;innodb_log_group_home_dir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* If your storage is fast (handle a lot of IOPS), you may want to adjust the &amp;lt;code&amp;gt;innodb_io_capacity&amp;lt;/code&amp;gt; setting, which defines a limit for the IOPS MySQL will create. The default is 200, which is sensible for single spindle disks. But if you have storage appliances with a lot of fast SAS drives, or even SSDs, this limit can be increased greatly.&lt;br /&gt;
&lt;br /&gt;
=== Functional items ===&lt;br /&gt;
&lt;br /&gt;
* Query cache is to be switched off; as we found in our own benchmarks and as backed up by upstreams, this hurts performance in load situations with high concurrency. [https://dev.mysql.com/doc/refman/5.7/en/query-cache.htm The query cache is deprecated as of MySQL 5.7.20, and is removed in MySQL 8.0], so we recommend also to switch that off.&lt;br /&gt;
* Starting with App Suite 7.10.0, &amp;lt;code&amp;gt;character_set_server&amp;lt;/code&amp;gt; must be set to &amp;lt;code&amp;gt;utf8mb4&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;collation_server&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;utf8mb4_general_ci&amp;lt;/code&amp;gt;&lt;br /&gt;
* Starting with MySQL 5.7 &amp;lt;code&amp;gt;innodb_strict_mode&amp;lt;/code&amp;gt; must be disabled.&lt;br /&gt;
* Starting with MySQL 5.7 and MariaDB 10.2 &amp;lt;code&amp;gt;sql_mode&amp;lt;/code&amp;gt; must be configured according to belows matrix.&lt;br /&gt;
&lt;br /&gt;
==== SQL mode matrix ====&lt;br /&gt;
&lt;br /&gt;
The default for the &amp;lt;code&amp;gt;sql_mode&amp;lt;/code&amp;gt; setting changes regularly with MariaDB and MySQL releases and is not even consistent anymore between the two derivates. SQL modes affect how data and queries are handled at runtime. Enabling strict modes might lead to errors in terms of failing queries or even update tasks. We strongly recommend the following configuration to avoid according runtime errors:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| sql_mode&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| App Suite 7.8.4&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| App Suite 7.10.0&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MySQL 5.6&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MySQL 5.7&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MariaDB 10.1&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MariaDB 10.2&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample config files ===&lt;br /&gt;
&lt;br /&gt;
For easy deployment we recommend not to edit existing the existing my.cnf file, rather assume the distro provides sane settings for most of the items and override items where needed.&lt;br /&gt;
&lt;br /&gt;
As in MySQL there is a [https://dev.mysql.com/doc/refman/5.7/en/option-files.html last instance wins] semantic in options file parsing, we propose to create a custom include directory &amp;quot;ox.conf.d&amp;quot;, put our custom config files therein, and include this directory as latest directory in /etc/mysql/my.cnf.&lt;br /&gt;
&lt;br /&gt;
To put in that directory, we have one main tuning file called tunings.cnf, one galera-related file if galera is in use, and one more galera host-specific file which contains per-host settings if using galera (separate in a file of its own for easier configuration management).&lt;br /&gt;
&lt;br /&gt;
So, start with adding to the existing my.cnf at the very bottom:&lt;br /&gt;
&lt;br /&gt;
 !includedir /etc/mysql/ox.conf.d/&lt;br /&gt;
&lt;br /&gt;
Create that directory and put in there the generic ox tunings file /etc/mysql/ox.conf.d/tunings.cnf:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 bind-address		 = *&lt;br /&gt;
 &lt;br /&gt;
 #innodb_use_native_aio = 0&lt;br /&gt;
 &lt;br /&gt;
 table_open_cache = 3072&lt;br /&gt;
 table_definition_cache = 4096&lt;br /&gt;
 max_heap_table_size = 64M&lt;br /&gt;
 tmp_table_size = 64M&lt;br /&gt;
 max_connections = 505&lt;br /&gt;
 max_user_connections = 500&lt;br /&gt;
 max_allowed_packet = 16M&lt;br /&gt;
 thread_cache_size = 32&lt;br /&gt;
 query_cache_size = 0&lt;br /&gt;
 query_cache_type = 0&lt;br /&gt;
 default_storage_engine = InnoDB&lt;br /&gt;
 innodb_buffer_pool_size = 32G&lt;br /&gt;
 # the default value in MySQL 5.6.6 and higher is 8 when innodb_buffer_pool_size is greater than or equal to 1GB. Otherwise, the default is 1. &lt;br /&gt;
 innodb_buffer_pool_instances = 32&lt;br /&gt;
 innodb_data_file_path = ibdata1:128M:autoextend&lt;br /&gt;
 innodb_file_per_table = 1&lt;br /&gt;
 # innodb_log_file_size should be 25% of the innodb_buffer_pool_size&lt;br /&gt;
 innodb_log_file_size = 4GB&lt;br /&gt;
 # default and recommended value is 2&lt;br /&gt;
 innodb_log_files_in_group = 2&lt;br /&gt;
 # adjust according to your storage&lt;br /&gt;
 #innodb_io_capacity = 1000&lt;br /&gt;
 &lt;br /&gt;
 # we are unsure about this setting. Newer versions of MariaDB seem to be fine with low (=1) settings for this value.&lt;br /&gt;
 # Traditionally we encountered values up to 4x the number of cores.&lt;br /&gt;
 # Default seems to be number of cores, so let's stick the default&lt;br /&gt;
 # In the end, we need to leave this setting up to you: if you dont get full cpu utilization in cpu-bound situations, this might be a setting to increase.&lt;br /&gt;
 #thread_pool_size = 32&lt;br /&gt;
 &lt;br /&gt;
 binlog_cache_size = 1M&lt;br /&gt;
 sync_binlog = 8&lt;br /&gt;
 binlog_format = row&lt;br /&gt;
 &lt;br /&gt;
 character_set_server = utf8&lt;br /&gt;
 collation_server = utf8_general_ci&lt;br /&gt;
 &lt;br /&gt;
 # This was default_table_type previous to MySQL 5.5&lt;br /&gt;
 default_storage_engine = InnoDB&lt;br /&gt;
 &lt;br /&gt;
 innodb_autoinc_lock_mode = 2&lt;br /&gt;
 &lt;br /&gt;
 # keep until 5.6, deprecated later&lt;br /&gt;
 innodb_locks_unsafe_for_binlog = 1&lt;br /&gt;
 &lt;br /&gt;
 # we found this has huge impact on (galera) performance&lt;br /&gt;
 # default (consistent) setting of 1 greatly severs performance&lt;br /&gt;
 # in galera (or async master-slave) deployments, you might be ok with setting this to 0 or 2,&lt;br /&gt;
 # assuming our consistency / availability comes from replication / other cluster nodes&lt;br /&gt;
 innodb_flush_log_at_trx_commit = 0&lt;br /&gt;
 &lt;br /&gt;
 # for performance testing systems, to not use excessive disk space&lt;br /&gt;
 #expire_logs_days = 1&lt;br /&gt;
 &lt;br /&gt;
 # MySQL 5.7.7 has changed the default to 1. Disable it explicitly to prevent from errors based on invalid data stored by former App Suite or MySQL versions.&lt;br /&gt;
 innodb_strict_mode = 0&lt;br /&gt;
 &lt;br /&gt;
 # The following value refers to App Suite 7.10 on top of MySQL 5.7. For other combinations see the sql mode matrix at http://oxpedia.org/wiki/index.php?title=My.cnf.&lt;br /&gt;
 sql_mode = NO_ENGINE_SUBSTITUTION,NO_AUTO_CREATE_USER,ONLY_FULL_GROUP_BY&lt;br /&gt;
&lt;br /&gt;
If using galera, use the following galera configuration file &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/wsrep.cnf&amp;lt;/code&amp;gt;. See the comments in that file for values to be adjusted.&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 # adjust for your distros SO location&lt;br /&gt;
 wsrep_provider=/usr/lib/libgalera_smm.so&lt;br /&gt;
 &lt;br /&gt;
 # this is the big winner and enables us to switch off OX's replication monitor&lt;br /&gt;
 wsrep_sync_wait=1&lt;br /&gt;
 &lt;br /&gt;
 # pick a unique cluster name&lt;br /&gt;
 wsrep_cluster_name=devcluster&lt;br /&gt;
 # adjust for your IPs / hostnames&lt;br /&gt;
 wsrep_cluster_address=gcomm://10.20.29.68,10.20.29.69,10.20.29.70&lt;br /&gt;
 &lt;br /&gt;
 # put this in host.cnf&lt;br /&gt;
 #wsrep_node_name=...&lt;br /&gt;
 #wsrep_node_address=...&lt;br /&gt;
 &lt;br /&gt;
 # For some MariaDB versions, xtrabackup-v2 no longer works, instead use &amp;quot;mariabackup&amp;quot;&lt;br /&gt;
 # (needs to be installed separately, e.g. via the mariadb-backup-10.2 package)&lt;br /&gt;
 # see upstream documentation for details: &lt;br /&gt;
 # https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/#xtrabackup&lt;br /&gt;
 #&lt;br /&gt;
 # wsrep_sst_method=mariabackup&lt;br /&gt;
 wsrep_sst_method=xtrabackup-v2&lt;br /&gt;
&lt;br /&gt;
 # wsrep_sst_auth if of format username:password&lt;br /&gt;
 # pick whatever you configured on the donor node&lt;br /&gt;
 wsrep_sst_auth=sstuser:...&lt;br /&gt;
 &lt;br /&gt;
 # galera-specific tunings&lt;br /&gt;
 wsrep_slave_threads = 32&lt;br /&gt;
 &lt;br /&gt;
 # finally, enable wsrep: required for some MariaDB versions&lt;br /&gt;
 wsrep_on=ON -- Enable wsrep replication (MariaDB starting 10.1.1) &lt;br /&gt;
&lt;br /&gt;
Galera-related host-specific settings go in /etc/mysql/ox.conf.d/host.cnf:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 # the nodes hostname&lt;br /&gt;
 wsrep_node_name=...&lt;br /&gt;
 # and the IP of the wsrep relevant interface, if multiple&lt;br /&gt;
 wsrep_node_address=10.20.29.68&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24294</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24294"/>
		<updated>2018-09-27T13:48:22Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* First node */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
That tool will ask for the current root password (which is empty by default) and subsequently questions like:&lt;br /&gt;
&lt;br /&gt;
 Change the root password? [Y/n]&lt;br /&gt;
 Remove anonymous users? [Y/n]&lt;br /&gt;
 Disallow root login remotely? [Y/n]&lt;br /&gt;
 Remove test database and access to it? [Y/n]&lt;br /&gt;
 Reload privilege tables now? [Y/n]&lt;br /&gt;
&lt;br /&gt;
You should answer all these questions with &amp;quot;yes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Configure a strong password for the MySQL &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; user.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 systemctl enable mysql.service&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1, 10.2&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # MariaDB 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Please use a real password.&lt;br /&gt;
* The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly.&lt;br /&gt;
* If using a database on the same host as the middlware (usually done for POCs and demo installations), you need to grant also to the ''localhost'' host.&lt;br /&gt;
* Consult [[AppSuite:DB_user_privileges]] (or ''grep GRANT /opt/open-xchange/sbin/initconfigdb'') for an up-to-date list of required privileges. The following statement was correct as of the time of writing this section.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24293</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24293"/>
		<updated>2018-09-27T13:35:03Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
That tool will ask for the current root password (which is empty by default) and subsequently questions like:&lt;br /&gt;
&lt;br /&gt;
 Change the root password? [Y/n]&lt;br /&gt;
 Remove anonymous users? [Y/n]&lt;br /&gt;
 Disallow root login remotely? [Y/n]&lt;br /&gt;
 Remove test database and access to it? [Y/n]&lt;br /&gt;
 Reload privilege tables now? [Y/n]&lt;br /&gt;
&lt;br /&gt;
You should answer all these questions with &amp;quot;yes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Configure a strong password for the MySQL &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; user.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 systemctl enable mysql.service&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # MariaDB 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Please use a real password.&lt;br /&gt;
* The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly.&lt;br /&gt;
* If using a database on the same host as the middlware (usually done for POCs and demo installations), you need to grant also to the ''localhost'' host.&lt;br /&gt;
* Consult [[AppSuite:DB_user_privileges]] (or ''grep GRANT /opt/open-xchange/sbin/initconfigdb'') for an up-to-date list of required privileges. The following statement was correct as of the time of writing this section.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=My.cnf&amp;diff=24284</id>
		<title>My.cnf</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=My.cnf&amp;diff=24284"/>
		<updated>2018-09-25T14:19:13Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page lists some performance tuning parameters which we recommend for tuning MySQL database services used for Open-Xchange installations.&lt;br /&gt;
&lt;br /&gt;
We cannot guarantee this is an exhaustive list of required settings. So treat this list of tunings as probably required, but not necessarily sufficient settings for optimal MySQL performance.&lt;br /&gt;
&lt;br /&gt;
Furthermore, as MySQL changes over time, settings which have been correct as of the time of writing may become incorrect later.&lt;br /&gt;
&lt;br /&gt;
However, this list of settings is the result of internal performance testing and real world customer feedback, so it should be valid to some extent.&lt;br /&gt;
&lt;br /&gt;
In the end, proper configuration of the database service for performance, but also consistency, durability and high availability is in the responsibility of the customer.&lt;br /&gt;
&lt;br /&gt;
=== Performance items ===&lt;br /&gt;
&lt;br /&gt;
* You should adjust the &amp;lt;code&amp;gt;innodb_buffer_pool_size&amp;lt;/code&amp;gt; parameter for reasonable memory usage. Our DB sizing is mainly memory-driven and this is where most of the memory goes. Our standard DB machine sizing assumption is 32 GB if MySQL dedicated memory on a 48 GB total memory machine. On such a machine, you would configure 32 GB for the innodb_buffer_pool size, being aware that MySQL does also require memory for other things, in particular there are some also per-connection related memory spendings, which can become substantial if you allow for a lot of maximum concurrent connections. Please watch your memory configuration carefully, use monitoring and tools like mysqltuner.pl.&lt;br /&gt;
&lt;br /&gt;
* On bigger installations you should use &amp;lt;code&amp;gt;innodb_file_per_table = 1&amp;lt;/code&amp;gt;, which is creating single files instead of one big blob. If you change this parameter after the database initialization you have to recreate (like dump/drop and re-import) the tables.&lt;br /&gt;
&lt;br /&gt;
* It can help to put different parts of the mysql datadir (iblog, ibdata) on different filesystems / storage devices. This depends on your infrastructure. Settings herefore are &amp;lt;code&amp;gt;datadir&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;innodb_data_home_dir&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;innodb_log_group_home_dir&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* If your storage is fast (handle a lot of IOPS), you may want to adjust the &amp;lt;code&amp;gt;innodb_io_capacity&amp;lt;/code&amp;gt; setting, which defines a limit for the IOPS MySQL will create. The default is 200, which is sensible for single spindle disks. But if you have storage appliances with a lot of fast SAS drives, or even SSDs, this limit can be increased greatly.&lt;br /&gt;
&lt;br /&gt;
=== Functional items ===&lt;br /&gt;
&lt;br /&gt;
* Query cache is to be switched off; as we found in our own benchmarks and as backed up by upstreams, this hurts performance in load situations with high concurrency. [https://dev.mysql.com/doc/refman/5.7/en/query-cache.htm The query cache is deprecated as of MySQL 5.7.20, and is removed in MySQL 8.0], so we recommend also to switch that off.&lt;br /&gt;
* Starting with App Suite 7.10.0, &amp;lt;code&amp;gt;character_set_server&amp;lt;/code&amp;gt; must be set to &amp;lt;code&amp;gt;utf8mb4&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;collation_server&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;utf8mb4_general_ci&amp;lt;/code&amp;gt;&lt;br /&gt;
* Starting with MySQL 5.7 &amp;lt;code&amp;gt;innodb_strict_mode&amp;lt;/code&amp;gt; must be disabled.&lt;br /&gt;
* Starting with MySQL 5.7 and MariaDB 10.2 &amp;lt;code&amp;gt;sql_mode&amp;lt;/code&amp;gt; must be configured according to belows matrix.&lt;br /&gt;
&lt;br /&gt;
==== SQL mode matrix ====&lt;br /&gt;
&lt;br /&gt;
The default for the &amp;lt;code&amp;gt;sql_mode&amp;lt;/code&amp;gt; setting changes regularly with MariaDB and MySQL releases and is not even consistent anymore between the two derivates. SQL modes affect how data and queries are handled at runtime. Enabling strict modes might lead to errors in terms of failing queries or even update tasks. We strongly recommend the following configuration to avoid according runtime errors:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| sql_mode&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| App Suite 7.8.4&lt;br /&gt;
! scope=&amp;quot;col&amp;quot;| App Suite 7.10.0&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MySQL 5.6&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MySQL 5.7&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MariaDB 10.1&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot;| MariaDB 10.2&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Sample config files ===&lt;br /&gt;
&lt;br /&gt;
For easy deployment we recommend not to edit existing the existing my.cnf file, rather assume the distro provides sane settings for most of the items and override items where needed.&lt;br /&gt;
&lt;br /&gt;
As in MySQL there is a [https://dev.mysql.com/doc/refman/5.7/en/option-files.html last instance wins] semantic in options file parsing, we propose to create a custom include directory &amp;quot;ox.conf.d&amp;quot;, put our custom config files therein, and include this directory as latest directory in /etc/mysql/my.cnf.&lt;br /&gt;
&lt;br /&gt;
To put in that directory, we have one main tuning file called tunings.cnf, one galera-related file if galera is in use, and one more galera host-specific file which contains per-host settings if using galera (separate in a file of its own for easier configuration management).&lt;br /&gt;
&lt;br /&gt;
So, start with adding to the existing my.cnf at the very bottom:&lt;br /&gt;
&lt;br /&gt;
 !includedir /etc/mysql/ox.conf.d/&lt;br /&gt;
&lt;br /&gt;
Create that directory and put in there the generic ox tunings file /etc/mysql/ox.conf.d/tunings.cnf:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 bind-address		 = *&lt;br /&gt;
 &lt;br /&gt;
 #innodb_use_native_aio = 0&lt;br /&gt;
 &lt;br /&gt;
 table_open_cache = 3072&lt;br /&gt;
 table_definition_cache = 4096&lt;br /&gt;
 max_heap_table_size = 64M&lt;br /&gt;
 tmp_table_size = 64M&lt;br /&gt;
 max_connections = 505&lt;br /&gt;
 max_user_connections = 500&lt;br /&gt;
 max_allowed_packet = 16M&lt;br /&gt;
 thread_cache_size = 32&lt;br /&gt;
 query_cache_size = 0&lt;br /&gt;
 query_cache_type = 0&lt;br /&gt;
 default_storage_engine = InnoDB&lt;br /&gt;
 innodb_buffer_pool_size = 32G&lt;br /&gt;
 # the default value in MySQL 5.6.6 and higher is 8 when innodb_buffer_pool_size is greater than or equal to 1GB. Otherwise, the default is 1. &lt;br /&gt;
 innodb_buffer_pool_instances = 32&lt;br /&gt;
 innodb_data_file_path = ibdata1:128M:autoextend&lt;br /&gt;
 innodb_file_per_table = 1&lt;br /&gt;
 # innodb_log_file_size should be 25% of the innodb_buffer_pool_size&lt;br /&gt;
 innodb_log_file_size = 4GB&lt;br /&gt;
 # default and recommended value is 2&lt;br /&gt;
 innodb_log_files_in_group = 2&lt;br /&gt;
 # adjust according to your storage&lt;br /&gt;
 #innodb_io_capacity = 1000&lt;br /&gt;
 &lt;br /&gt;
 # we are unsure about this setting. Newer versions of MariaDB seem to be fine with low (=1) settings for this value.&lt;br /&gt;
 # Traditionally we encountered values up to 4x the number of cores.&lt;br /&gt;
 # Default seems to be number of cores, so let's stick the default&lt;br /&gt;
 # In the end, we need to leave this setting up to you: if you dont get full cpu utilization in cpu-bound situations, this might be a setting to increase.&lt;br /&gt;
 #thread_pool_size = 32&lt;br /&gt;
 &lt;br /&gt;
 binlog_cache_size = 1M&lt;br /&gt;
 sync_binlog = 8&lt;br /&gt;
 binlog_format = row&lt;br /&gt;
 &lt;br /&gt;
 character_set_server = utf8&lt;br /&gt;
 collation_server = utf8_general_ci&lt;br /&gt;
 &lt;br /&gt;
 # This was default_table_type previous to MySQL 5.5&lt;br /&gt;
 default_storage_engine = InnoDB&lt;br /&gt;
 &lt;br /&gt;
 innodb_autoinc_lock_mode = 2&lt;br /&gt;
 &lt;br /&gt;
 # keep until 5.6, deprecated later&lt;br /&gt;
 innodb_locks_unsafe_for_binlog = 1&lt;br /&gt;
 &lt;br /&gt;
 # we found this has huge impact on (galera) performance&lt;br /&gt;
 # default (consistent) setting of 1 greatly severs performance&lt;br /&gt;
 # in galera (or async master-slave) deployments, you might be ok with setting this to 0 or 2,&lt;br /&gt;
 # assuming our consistency / availability comes from replication / other cluster nodes&lt;br /&gt;
 innodb_flush_log_at_trx_commit = 0&lt;br /&gt;
 &lt;br /&gt;
 # for performance testing systems, to not use excessive disk space&lt;br /&gt;
 #expire_logs_days = 1&lt;br /&gt;
 &lt;br /&gt;
 # MySQL 5.7.7 has changed the default to 1. Disable it explicitly to prevent from errors based on invalid data stored by former App Suite or MySQL versions.&lt;br /&gt;
 innodb_strict_mode = 0&lt;br /&gt;
 &lt;br /&gt;
 # The following value refers to App Suite 7.10 on top of MySQL 5.7. For other combinations see the sql mode matrix at http://oxpedia.org/wiki/index.php?title=My.cnf.&lt;br /&gt;
 sql_mode = NO_ENGINE_SUBSTITUTION,NO_AUTO_CREATE_USER,ONLY_FULL_GROUP_BY&lt;br /&gt;
&lt;br /&gt;
If using galera, use the following galera configuration file /etc/mysql/ox.conf.d/wsrep.cnf:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 # adjust for your distros SO location&lt;br /&gt;
 wsrep_provider=/usr/lib/libgalera_smm.so&lt;br /&gt;
 &lt;br /&gt;
 # this is the big winner and enables us to switch off OX's replication monitor&lt;br /&gt;
 wsrep_sync_wait=1&lt;br /&gt;
 &lt;br /&gt;
 # pick a unique cluster name&lt;br /&gt;
 wsrep_cluster_name=devcluster&lt;br /&gt;
 # adjust for your IPs / hostnames&lt;br /&gt;
 wsrep_cluster_address=gcomm://10.20.29.68,10.20.29.69,10.20.29.70&lt;br /&gt;
 &lt;br /&gt;
 # put this in host.cnf&lt;br /&gt;
 #wsrep_node_name=...&lt;br /&gt;
 #wsrep_node_address=...&lt;br /&gt;
 &lt;br /&gt;
 wsrep_sst_method=xtrabackup-v2&lt;br /&gt;
 # wsrep_sst_auth if of format username:password&lt;br /&gt;
 # pick whatever you configured on the donor node&lt;br /&gt;
 wsrep_sst_auth=sstuser:...&lt;br /&gt;
 &lt;br /&gt;
 # galera-specific tunings&lt;br /&gt;
 wsrep_slave_threads = 32&lt;br /&gt;
&lt;br /&gt;
Galera-related host-specific settings go in /etc/mysql/ox.conf.d/host.cnf:&lt;br /&gt;
&lt;br /&gt;
 [mysqld]&lt;br /&gt;
 # the nodes hostname&lt;br /&gt;
 wsrep_node_name=...&lt;br /&gt;
 # and the IP of the wsrep relevant interface, if multiple&lt;br /&gt;
 wsrep_node_address=10.20.29.68&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24243</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24243"/>
		<updated>2018-09-06T13:50:40Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
That tool will ask for the current root password (which is empty by default) and subsequently questions like:&lt;br /&gt;
&lt;br /&gt;
 Change the root password? [Y/n]&lt;br /&gt;
 Remove anonymous users? [Y/n]&lt;br /&gt;
 Disallow root login remotely? [Y/n]&lt;br /&gt;
 Remove test database and access to it? [Y/n]&lt;br /&gt;
 Reload privilege tables now? [Y/n]&lt;br /&gt;
&lt;br /&gt;
You should answer all these questions with &amp;quot;yes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Configure a strong password for the MySQL &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; user.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 systemctl enable mysql.service&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/pre&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # MariaDB 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Please use a real password.&lt;br /&gt;
* The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly.&lt;br /&gt;
* If using a database on the same host as the middlware (usually done for POCs and demo installations), you need to grant also to the ''localhost'' host.&lt;br /&gt;
* Consult [[AppSuite:DB_user_privileges]] (or ''grep GRANT /opt/open-xchange/sbin/initconfigdb'') for an up-to-date list of required privileges. The following statement was correct as of the time of writing this section.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24242</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24242"/>
		<updated>2018-09-06T13:50:17Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
That tool will ask for the current root password (which is empty by default) and subsequently questions like:&lt;br /&gt;
&lt;br /&gt;
 Change the root password? [Y/n]&lt;br /&gt;
 Remove anonymous users? [Y/n]&lt;br /&gt;
 Disallow root login remotely? [Y/n]&lt;br /&gt;
 Remove test database and access to it? [Y/n]&lt;br /&gt;
 Reload privilege tables now? [Y/n]&lt;br /&gt;
&lt;br /&gt;
You should answer all these questions with &amp;quot;yes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Configure a strong password for the MySQL &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; user.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 systemctl enable mysql.service&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/pre&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Please use a real password.&lt;br /&gt;
* The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly.&lt;br /&gt;
* If using a database on the same host as the middlware (usually done for POCs and demo installations), you need to grant also to the ''localhost'' host.&lt;br /&gt;
* Consult [[AppSuite:DB_user_privileges]] (or ''grep GRANT /opt/open-xchange/sbin/initconfigdb'') for an up-to-date list of required privileges. The following statement was correct as of the time of writing this section.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24241</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24241"/>
		<updated>2018-09-06T13:49:46Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # mariadb 10.2&lt;br /&gt;
 mysql_install_db --user=mysql&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
That tool will ask for the current root password (which is empty by default) and subsequently questions like:&lt;br /&gt;
&lt;br /&gt;
 Change the root password? [Y/n]&lt;br /&gt;
 Remove anonymous users? [Y/n]&lt;br /&gt;
 Disallow root login remotely? [Y/n]&lt;br /&gt;
 Remove test database and access to it? [Y/n]&lt;br /&gt;
 Reload privilege tables now? [Y/n]&lt;br /&gt;
&lt;br /&gt;
You should answer all these questions with &amp;quot;yes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Configure a strong password for the MySQL &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; user.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 systemctl enable mysql.service&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/pre&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Please use a real password.&lt;br /&gt;
* The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly.&lt;br /&gt;
* If using a database on the same host as the middlware (usually done for POCs and demo installations), you need to grant also to the ''localhost'' host.&lt;br /&gt;
* Consult [[AppSuite:DB_user_privileges]] (or ''grep GRANT /opt/open-xchange/sbin/initconfigdb'') for an up-to-date list of required privileges. The following statement was correct as of the time of writing this section.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Tune_apache2_for_more_concurrent_connections&amp;diff=24238</id>
		<title>Tune apache2 for more concurrent connections</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Tune_apache2_for_more_concurrent_connections&amp;diff=24238"/>
		<updated>2018-09-06T10:11:51Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Apache Configuration =&lt;br /&gt;
&lt;br /&gt;
== MPM Module ==&lt;br /&gt;
&lt;br /&gt;
Please ensure that your apache is using the &amp;lt;code&amp;gt;mpm_worker&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;mpm_event&amp;lt;/code&amp;gt; module. This allows us to serve lots of concurrent connections by using less RAM than with &amp;lt;code&amp;gt;mpm_prefork&amp;lt;/code&amp;gt; as we are going to start much less processes. Unfortunately the default MPM module seems to differ from distro to distro, so doublecheck and make sure you are on the right setting.&lt;br /&gt;
&lt;br /&gt;
The method to configure the MPM module differes of course also from distribution to distribution:&lt;br /&gt;
&lt;br /&gt;
* CentOS7/RHEL7: adjust &amp;lt;code&amp;gt;/etc/httpd/conf.modules.d/00-mpm.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
* Debian: use &amp;lt;code&amp;gt;a2dismod&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;a2enmod&amp;lt;/code&amp;gt; to disable the wrong and enable the desired MPM Module.&lt;br /&gt;
&lt;br /&gt;
About &amp;lt;code&amp;gt;mpm_worker&amp;lt;/code&amp;gt; vs &amp;lt;code&amp;gt;mpm_event&amp;lt;/code&amp;gt;: we assume they are equivalent for our purpose. &amp;lt;code&amp;gt;mpm_worker&amp;lt;/code&amp;gt; is the older one and just works fine. &amp;lt;code&amp;gt;mpm_event&amp;lt;/code&amp;gt; should improve on it further but we have been unable to observe any actual advantages.&lt;br /&gt;
&lt;br /&gt;
== Concurrent Connections == &lt;br /&gt;
&lt;br /&gt;
By default apache2 is configured to support 150 concurrent connections.&lt;br /&gt;
This forces all parallel requests beyond that limit to wait. &lt;br /&gt;
Especially if, for example, active sync clients maintain a permanent connection for push events to arrive.&lt;br /&gt;
&lt;br /&gt;
This is an example configuration to provide 8000 concurrent connections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;IfModule mpm_worker_module&amp;gt;&lt;br /&gt;
    ServerLimit              250&lt;br /&gt;
    StartServers              10&lt;br /&gt;
    MinSpareThreads           75&lt;br /&gt;
    MaxSpareThreads          250 &lt;br /&gt;
    ThreadLimit               64&lt;br /&gt;
    ThreadsPerChild           32&lt;br /&gt;
    MaxRequestWorkers       8000&lt;br /&gt;
    MaxConnectionsPerChild 10000&lt;br /&gt;
&amp;lt;/IfModule&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: MaxRequestWorkers was previously named MaxClients and MaxConnectionsPerChild was previously named MaxRequestsPerChild. If you are using old (pre 2.4) verions of apache you might need to use the old names.&lt;br /&gt;
&lt;br /&gt;
Short explanation of the parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;ServerLimit&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Declares the maximum number of running apache processes. If you change this value you have to restart the daemon.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;StartServers&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;The number of processes to start initially when starting the apache daemon.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;MinSpareThreads/MaxSpareThreads&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;This regulates how many threads may stay idle without being killed. Apache regulates this on its own very well with default values.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;ThreadsPerChild&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;How many threads can be created per process. Can be changed during a reload.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;ThreadLimit&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;ThreadsPerChild&amp;lt;/b&amp;gt; can be configured as high as this value during runtime. If you change this value you have to restart the daemon.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;MaxRequestWorkers&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;This declares how many concurrent connections we provide. Devided by '''ThreadsPerChild'''  you get the suitable ServerLimit value. May be less than '''ServerLimit * ThreadsPerChild''' to reserve some resources that can be engaged during runtime with increasing '''MaxRequestWorkers''' and reloading the configuration.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;MaxConnectionsPerChild&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Defines the number of Connections that a process can handle during its lifetime (keep-alives are counted once). After that it will be killed. This can be used to prevent possible apache memory leaks. If set to 0 the lifetime is infinite.&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For further information on these parameters see http://httpd.apache.org/docs/2.4/mod/worker.html and http://httpd.apache.org/docs/2.4/mod/mpm_common.html.&lt;br /&gt;
&lt;br /&gt;
--[[User:Steffen.templin|Steffen.templin]] 12:10, 23 May 2011 (UTC)&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=HAproxy&amp;diff=24178</id>
		<title>HAproxy</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=HAproxy&amp;diff=24178"/>
		<updated>2018-07-18T14:24:08Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= HAproxy Loadbalancer =&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
HAproxy is a mature and popular option for userspace loadbalancing under Linux (and similar operating systems). Its main (original) purpose is probably HTTP load balancing.&lt;br /&gt;
&lt;br /&gt;
In Open-Xchange installations, for loadbalancing (reverse proxying) user session HTTP traffic towards our middleware, we require Apache, for reasons of correct handling of HTTP sticky sessions. See the corresponding &amp;quot;Configure Services&amp;quot; sections in our &lt;br /&gt;
[[AppSuite:Main_Page_Quickinstall#Quick_Installation_Guide|Quickinstall Guides]] for reference,  [[AppSuite:Open-Xchange_Installation_Guide_for_CentOS_7#Configure_services|e.g. the CentOS version]].&lt;br /&gt;
&lt;br /&gt;
Thus, in Open-Xchange installations HAproxy thus typically acts in other roles:&lt;br /&gt;
&lt;br /&gt;
* As front-level loadbalancer in front of the Apache instances (in enterprise installations, however, usually other software is employed for that purpose), or&lt;br /&gt;
* As loadbalancer for connecting the OX middleware to the database (Galera) instances, or&lt;br /&gt;
* As loadbalancer for connecting [[AppSuite:Dovecot_Antiabuse_Shield|Dovecot Anti Abuse Shield]] to Dovecot and App Suite&lt;br /&gt;
&lt;br /&gt;
We will cover in this article the latter two use cases.&lt;br /&gt;
&lt;br /&gt;
== Software Installation ==&lt;br /&gt;
&lt;br /&gt;
This is generic for the different use cases and thus described generically here.&lt;br /&gt;
&lt;br /&gt;
HAproxy should be shipped with the distribution.&lt;br /&gt;
&lt;br /&gt;
Historical Wheezy note: haproxy is provided in wheezy-backports, see http://haproxy.debian.net/. More recent (Debian) distributions don't need this extra repo and provide it with their native repos.&lt;br /&gt;
&lt;br /&gt;
 # yum install haproxy&lt;br /&gt;
 # apt-get install haproxy&lt;br /&gt;
&lt;br /&gt;
== HAproxy for DAAS / wforce Loadbalancing ==&lt;br /&gt;
&lt;br /&gt;
In the following we present a configuration which was feedbacked to us from a large customer installation. (Thanks a lot!)&lt;br /&gt;
&lt;br /&gt;
Crucial are the following aspects:&lt;br /&gt;
&lt;br /&gt;
* Detect capacity issues on the wforce backends to be resilient to DOS attacks&lt;br /&gt;
* In case of capacity issues, just do a HTTP deny. It makes no sense to use some cross-datacenter routing (if multiple datacenters are available) as the latency combined with the query volume makes this less then ideal. A tiny amount of unanswered calls is fine, and doesn't affect the auth process or user experience.&lt;br /&gt;
* Timeouts are such that HAproxy's timeout (35 msecs(!)) is smaller than the corresponding wforce service consumer timeout (e.g. &amp;lt;code&amp;gt;dovecot&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;auth_policy_server_timeout_msecs&amp;lt;/code&amp;gt; would get a corresponding value of 100 msecs). In this way timeouts are a little more often, but graceful and have little to no impact on user experience.&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
 frontend wforce :8084&lt;br /&gt;
         mode http&lt;br /&gt;
         # detect capacity issues in wforce backend&lt;br /&gt;
         acl local_wforce_not_enough_capacity nbsrv(wforce_backend_primary) lt 2&lt;br /&gt;
         # deny request if primary backend doesn't have capacity&lt;br /&gt;
         http-request deny if local_wforce_not_enough_capacity&lt;br /&gt;
         default_backend wforce_backend_primary&lt;br /&gt;
 &lt;br /&gt;
 backend wforce_backend_primary&lt;br /&gt;
         balance leastconn&lt;br /&gt;
         mode http&lt;br /&gt;
         timeout connect 35&lt;br /&gt;
         timeout server 30s&lt;br /&gt;
         timeout check 0&lt;br /&gt;
         option httpchk GET /?command=ping HTTP/1.0\r\nAuthorization:\ Basic\ --redacted--&lt;br /&gt;
         option http-keep-alive&lt;br /&gt;
         server wforce-01.example.net 192.168.0.1:8084 weight 10 check inter 5000 fall 5 rise 3&lt;br /&gt;
         server wforce-02.example.net 192.168.0.2:8084 weight 10 check inter 5000 fall 5 rise 3&lt;br /&gt;
         server wforce-03.example.net 192.168.0.3:8084 weight 10 check inter 5000 fall 5 rise 3&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
== HAproxy for Galera Loadbalancing ==&lt;br /&gt;
&lt;br /&gt;
HAproxy is one of the options to use for [[OXLoadBalancingClustering_Database#Galera_database_setup|Galera]] loadbalancing. Please consider reading through [[OXLoadBalancingClustering_Database#Loadbalancer_options|the available options]] before deciding for one solution.&lt;br /&gt;
&lt;br /&gt;
=== System Design ===&lt;br /&gt;
&lt;br /&gt;
We present a solution where each OX node runs a HAproxy instance. This way we can implement a solution without the need for additional loadbalancer (virtual) machines.&lt;br /&gt;
&lt;br /&gt;
We create two HAproxy &amp;quot;listener&amp;quot;, one round-robin for the read requests, one active/passive for the write requests.&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
The following is a HAproxy configuration file &amp;lt;code&amp;gt;/etc/haproxy/haproxy.cfg&amp;lt;/code&amp;gt;, assuming the Galera nodes have the IPs 10.0.0.1..3.&lt;br /&gt;
&lt;br /&gt;
  global&lt;br /&gt;
      log 127.0.0.1     local0&lt;br /&gt;
      log 127.0.0.1     local1 notice&lt;br /&gt;
      user              haproxy&lt;br /&gt;
      group             haproxy&lt;br /&gt;
      # this is not recommended by the haproxy authors, but seems to improve performance for me&lt;br /&gt;
      #nbproc 4&lt;br /&gt;
      maxconn           256000&lt;br /&gt;
      spread-checks     5&lt;br /&gt;
      daemon&lt;br /&gt;
      stats socket      /var/lib/haproxy/stats &lt;br /&gt;
  &lt;br /&gt;
  defaults&lt;br /&gt;
      log               global&lt;br /&gt;
      retries           3&lt;br /&gt;
      maxconn           256000&lt;br /&gt;
      timeout connect   60000&lt;br /&gt;
      timeout client    20m&lt;br /&gt;
      timeout server    20m&lt;br /&gt;
      option            dontlognull&lt;br /&gt;
      option            redispatch&lt;br /&gt;
      # the http options are not needed here&lt;br /&gt;
      # but may be reasonable if you use haproxy also for some OX HTTP proxying&lt;br /&gt;
      mode              http&lt;br /&gt;
      no option         httpclose&lt;br /&gt;
  &lt;br /&gt;
  listen mysql-read&lt;br /&gt;
      bind 127.0.0.1:3306&lt;br /&gt;
      mode tcp&lt;br /&gt;
      balance roundrobin&lt;br /&gt;
      option httpchk GET /&lt;br /&gt;
      server db1 10.0.0.1:3306 check port 9200 inter 6000 rise 3 fall 3&lt;br /&gt;
      server db2 10.0.0.2:3306 check port 9200 inter 6000 rise 3 fall 3&lt;br /&gt;
      server db3 10.0.0.3:3306 check port 9200 inter 6000 rise 3 fall 3&lt;br /&gt;
  &lt;br /&gt;
  listen mysql-write&lt;br /&gt;
      bind 127.0.0.1:3307&lt;br /&gt;
      mode tcp&lt;br /&gt;
      balance roundrobin&lt;br /&gt;
      option httpchk GET /master&lt;br /&gt;
      # maybe be more prudent with the master for the fall parameter&lt;br /&gt;
      server db1 10.0.0.1:3306 check port 9200 inter 6000 rise 3 fall 1&lt;br /&gt;
      server db2 10.0.0.2:3306 check port 9200 inter 6000 rise 3 fall 1&lt;br /&gt;
      server db3 10.0.0.3:3306 check port 9200 inter 6000 rise 3 fall 1&lt;br /&gt;
  &lt;br /&gt;
  #&lt;br /&gt;
  # can configure a stats interface here, but if you do so,&lt;br /&gt;
  # change the username / password&lt;br /&gt;
  #&lt;br /&gt;
  #listen stats&lt;br /&gt;
  #    bind 0.0.0.0:8080&lt;br /&gt;
  #    mode http&lt;br /&gt;
  #    stats enable&lt;br /&gt;
  #    stats uri /&lt;br /&gt;
  #    stats realm Strictly\ Private&lt;br /&gt;
  #    stats auth user:pass&lt;br /&gt;
&lt;br /&gt;
Note 1: the timeout options may seem exaggerated high, but they are required to ensure that it is not the loadbalancer shutting down MySQL connections while the systems still use it. Cf. &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 # Maximum time in milliseconds a connection will be used. After this time&lt;br /&gt;
 # the connection get closed.&lt;br /&gt;
 maxLifeTime=600000&lt;br /&gt;
&lt;br /&gt;
We got a default of 10 minutes, so allowing for some extra time to allow running queries to finish plus some overhead, 20 minutes look like a reasonable value for the connection timeout here.&lt;br /&gt;
&lt;br /&gt;
Note 2: If you are configuring a dedicated loadbalancer node which should loadbalancer for other clients on the network (rather than a distributed / colocated HAproxy instance which should only serve for localhost) change the &amp;lt;code&amp;gt;bind&amp;lt;/code&amp;gt; parameters accordingly.&lt;br /&gt;
&lt;br /&gt;
=== Health check service ===&lt;br /&gt;
&lt;br /&gt;
As you can see we use the &amp;lt;code&amp;gt;httpchk&amp;lt;/code&amp;gt; option, so we assume a health check service to be available. Please have a look at the [[Clustercheck]] page how to configure such a service. Please be aware that we assume you use our customized, improved [[Clustercheck|&amp;lt;code&amp;gt;clustercheck&amp;lt;/code&amp;gt;]] script, so please don't use the standard one.&lt;br /&gt;
&lt;br /&gt;
Contrary to other setup instructions which recommend to configure one node as ''regular'' node and the other two ones as &amp;lt;code&amp;gt;backup&amp;lt;/code&amp;gt; nodes, we recommend to leverage a health check which declares only the node with &amp;lt;code&amp;gt;wsrep_local_index=0&amp;lt;/code&amp;gt; as available. This way we ensure that even in corner cases, multiple distributed HAproxy instances can not end up with declaring different nodes as designated write nodes, which [[OXLoadBalancingClustering_Database#Write_requests|would be problematic]].&lt;br /&gt;
&lt;br /&gt;
=== Monitoring ===&lt;br /&gt;
&lt;br /&gt;
Besided using the Galera check service configured before, you can also speak to the stats socket of HAproxy using &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 # echo &amp;quot;show stat&amp;quot; | socat unix-connect:/var/lib/haproxy/stats stdio&lt;br /&gt;
&lt;br /&gt;
The output is a CSV with long lines unsuitable for pasting here. Please test on your own.&lt;br /&gt;
&lt;br /&gt;
There are more commands available via this socket to enable / disable servers; see the haproxy documentation for details. (As of writing that documentation could be found here: http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#9.2 that URL seems unstable.)&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:7_10_Database_Migration&amp;diff=24153</id>
		<title>AppSuite:7 10 Database Migration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:7_10_Database_Migration&amp;diff=24153"/>
		<updated>2018-07-06T08:43:59Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Initial OX App Suite v7.10.0 Rollout */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Version|7.10.0}}&lt;br /&gt;
&lt;br /&gt;
= Database Migration with OX App Suite v7.10.0 =&lt;br /&gt;
&lt;br /&gt;
OX App Suite v7.10.0 introduces significant changes regarding the underlying MySQL database system that require special attention in case of upgrades from former versions. Please read this paper carefully to ensure a smooth and clean upgrade process.&lt;br /&gt;
&lt;br /&gt;
== Change Overview ==&lt;br /&gt;
&lt;br /&gt;
The most significant changes are:&lt;br /&gt;
* New version and configuration requirements.&lt;br /&gt;
* Most VARCHAR columns need to be migrated to utf8mb4 character encoding.&lt;br /&gt;
* A major rewrite of the calendar application requires full data migration.&lt;br /&gt;
&lt;br /&gt;
We strongly recommend to thoroughly plan and test the upgrade procedure. To gain insights about update task runtimes and the expected load, our recommendation is to clone ConfigDB and the biggest UserDB and perform an isolated test upgrade that especially covers the calendar migration and character encoding changes. Update task durations can be significantly longer than with previous upgrades and the migrations might cause noticeable higher I/O load. Also some additional disk space is needed during and after the migrations.&lt;br /&gt;
&lt;br /&gt;
== Database System ==&lt;br /&gt;
&lt;br /&gt;
MySQL Server is supported in versions 5.6 and 5.7 with recent patch levels only and MariaDB Server 10.1 and 10.2 respectively. Support for 5.6/10.1 exists for compatibility reasons and is transitional. We recommend upgrading to 5.7/10.2 as soon as possible. Any database system upgrade must happen before App Suite is upgraded to OX App Suite v7.10.0. Please follow the respective guides of your database vendor carefully.&lt;br /&gt;
&lt;br /&gt;
Different App Suite and database system versions require different configurations of the DBMS, please follow http://oxpedia.org/wiki/index.php?title=My.cnf to have your database configured in a sane way. Especially the following items require some attention with the upgrade to App Suite 7.10.0 and upgrades of the DBMS itself:&lt;br /&gt;
&lt;br /&gt;
* Supported SQL modes are only &amp;lt;code&amp;gt;NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER&amp;lt;/code&amp;gt;. Starting with App Suite 7.10.0, &amp;lt;code&amp;gt;ONLY_FULL_GROUP_BY&amp;lt;/code&amp;gt; is also supported for MySQL 5.7. It is still not with older versions of MySQL or any MariaDB version! To review the current value, use &amp;lt;code&amp;gt;SHOW GLOBAL VARIABLES WHERE Variable_name = 'sql_mode';&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensure that &amp;lt;code&amp;gt;character_set_server&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;utf8&amp;lt;/code&amp;gt; for App Suite 7.8.x. Again the current global default value can be obtained via &amp;lt;code&amp;gt;SHOW GLOBAL VARIABLES WHERE Variable_name = 'character_set_server';&amp;lt;/code&amp;gt;. With 7.10.0 being fully rolled out, this setting must then be changed to &amp;lt;code&amp;gt;utf8mb4&amp;lt;/code&amp;gt;. If &amp;lt;code&amp;gt;collation_server&amp;lt;/code&amp;gt; is configured explicitly, it must be set to a matching value according to the character set in either case!&lt;br /&gt;
&lt;br /&gt;
Note that App Suite &amp;lt;= 7.8.4 did not support MySQL 5.7/MariaDB 10.2 so far. While we recommend it for 7.10.0, this leaves a lack of definition during the upgrade process. We consider running 7.8.4 on top of MySQL 5.7/MariaDB 10.2 a valid scenario as long as it is transitional during the upgrade phase. Please take our configuration recommendations seriously to mitigate potential user-facing issues as far as possible.&lt;br /&gt;
&lt;br /&gt;
== Upgrade Procedure ==&lt;br /&gt;
&lt;br /&gt;
The upgrade to OX App Suite v7.10.0 can be performed like any other major upgrade before. However, the duration of blocking database update tasks for the mentioned charset and calendar migrations could conflict with customers’ availability demands. Therefore it is possible to decouple these special time- and resource-intensive tasks from the plain version upgrade. In this section a multi-step approach is described that performs the version upgrade before and independently from the migrations. Every step always results in a working system that is ready to serve user traffic. Some functional implications that affect user experience are outlined in the according subsections.&lt;br /&gt;
&lt;br /&gt;
'''Important:''' Even though the first step leads to a basically working OX App Suite v7.10.0 environment, the subsequent steps are not optional but mandatory! Skipping the migrations will leave a few calendar features dysfunctional and can lead to issues with certain SQL queries that use explicit collations for searching and sorting. Running OX App Suite v7.10.0 in production without having all parts of the migration fulfilled is not supported – OX support will request you to complete the migration tasks when reporting issues that are not related to the migration itself. &lt;br /&gt;
&lt;br /&gt;
== Initial OX App Suite v7.10.0 Rollout ==&lt;br /&gt;
If not done so far, upgrade your MySQL installation to a version supported with OX App Suite v7.10.0 but configure it to be compatible with OX App Suite v7.8.x as described in the “Database System” section.&lt;br /&gt;
&lt;br /&gt;
Despite the fact that the two special migrations for calendar and character sets are explicitly skipped, this section assumes that the “Rolling Upgrade with breaking Hazelcast upgrade” is applied as described in http://oxpedia.org/wiki/index.php?title=AppSuite:Running_a_cluster#Updating_a_Cluster. For the application server upgrade, the common guide from http://oxpedia.org/wiki/index.php?title=AppSuite:UpdatingOXPackages can be followed.&lt;br /&gt;
&lt;br /&gt;
Prepare a dedicated App Suite middleware node that will be used to perform the database update tasks. The node must not be serving any user traffic and be prepared with&lt;br /&gt;
&lt;br /&gt;
* OX App Suite v7.10.0 packages&lt;br /&gt;
* Configuration according to the user production nodes&lt;br /&gt;
* The Hazelcast rolling upgrade compatibility package (see http://oxpedia.org/wiki/index.php?title=AppSuite:Running_a_cluster#Rolling_Upgrade_with_breaking_Hazelcast_upgrade)&lt;br /&gt;
* Exclude the update tasks for both mentioned migrations (i.e. calendar and character encoding). See “Update Task Exclusion” for details.&lt;br /&gt;
* Execute update tasks according to your preferred strategy. More on this can be found at http://oxpedia.org/wiki/index.php?title=UpdateTasks.&lt;br /&gt;
&lt;br /&gt;
By default (if using the &amp;quot;runallupdate&amp;quot; tool&amp;quot;) update tasks operate on database schemas sequentially, one at a time. All users from all contexts of a given schema are logged out and locked out. Then, DB schema changes are executed. Finally, users are unlocked and able to login again. Schemas typically contain a few thousand users (if our recommended sizing is being followed) and thus executing update tasks means bunches of a few thousand users will be affected sequentially. You will not have a full downtime. For each update task execution process the following statements hold true:&lt;br /&gt;
&lt;br /&gt;
* All users got service for nearly all the time (all the time but the time where their schema is upgraded)&lt;br /&gt;
* For each point in time, nearly all users got service (all but the ones from the currently updated schema)&lt;br /&gt;
* When update tasks are completed, all users will have been affected by one &amp;quot;logout&amp;quot; - &amp;quot;locked out&amp;quot; cycle&lt;br /&gt;
&lt;br /&gt;
After complete and successful update task execution, roll out OX App Suite v7.10.0 to one node after another. After complete rollout, reconfigure MySQL if appropriate as described in the “Database System” section.&lt;br /&gt;
&lt;br /&gt;
=== Update Task Exclusion ===&lt;br /&gt;
&lt;br /&gt;
Add the following lines to &amp;lt;code&amp;gt;/opt/open-xchange/etc/excludedupdatetasks.properties&amp;lt;/code&amp;gt; or remove the leading # character if already included, so that it contains these two lines:&lt;br /&gt;
&lt;br /&gt;
 # Character Encoding Migration&lt;br /&gt;
 com.openexchange.groupware.update.excludedUpdateTasks=groupware.utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 # Calendar Migration&lt;br /&gt;
 com.openexchange.chronos.storage.rdb.migration.ChronosStorageMigrationTask&lt;br /&gt;
&lt;br /&gt;
The first line does not denote one dedicated update task, but a whole list of tasks. To make exclusion more convenient, the concept of update task namespaces has been introduced. All update tasks belonging to the character encoding migration are part of the &amp;lt;code&amp;gt;groupware.utf8mb4&amp;lt;/code&amp;gt; namespace. The denoted property takes care of excluding them all at once. You can list all according tasks with the &amp;lt;code&amp;gt;/opt/open-xchange/sbin/listUpdateTaskNamespaces&amp;lt;/code&amp;gt; tool.&lt;br /&gt;
&lt;br /&gt;
== Character Encoding Migration ==&lt;br /&gt;
&lt;br /&gt;
The default character encoding for Unicode (named character set by MySQL) of MySQL will become &amp;lt;code&amp;gt;utf8mb4&amp;lt;/code&amp;gt; in the near future. MariaDB on Debian Stretch (9) already has an according default configuration set when installing it from distribution packages. So far all VARCHAR columns are supposed to store at max. 3-byte UTF-8 characters due to the nature of MySQL’s utf8 character encoding. This leads to the fact that for example emojis cannot be saved as part of any App Suite entities. In a mixed-mode scenario (App Suite considers MySQL to operate in utf8mb4 mode due to the &amp;lt;code&amp;gt;character_set_server&amp;lt;/code&amp;gt; setting, while columns are specified with utf8 encoding), this leads to issues whenever certain collations during SELECT statements are enforced. To avoid such issues generally and also increase user experience by finally allowing characters from the Unicode astral plane, Open-Xchange has decided to migrate existing data structures to the utf8mb4 character encoding.&lt;br /&gt;
&lt;br /&gt;
This migration can be executed before or after the calendar migration, while it is recommend to execute it before.&lt;br /&gt;
&lt;br /&gt;
The upgrade procedure is basically the same as above in terms executing update tasks, while the server software is already up to date and needs no further upgrades:&lt;br /&gt;
&lt;br /&gt;
* Again prepare one dedicated node that doesn’t serve any user traffic&lt;br /&gt;
* Remove the according namespace property from &amp;lt;code&amp;gt;excludedupdatetasks.properties&amp;lt;/code&amp;gt; again, but still keep the “ChronosStorageMigrationTask”. Afterwards restart the open-xchange daemon.&lt;br /&gt;
* Execute update tasks according to your preferred strategy.&lt;br /&gt;
&lt;br /&gt;
'''Important:''' The update tasks require a lot of tables to be copied and re-created, leading to high I/O and especially sequential read and write operations. For every copied table the needed MySQL disk space doubles during the update task, so ensure enough free space before running the migration.&lt;br /&gt;
&lt;br /&gt;
== Calendar Data Migration ==&lt;br /&gt;
&lt;br /&gt;
The new calendar stack in OX App Suite v7.10.0 comes along with a new data model using its very own tables in MySQL. To preserve users calendar data, an update task &amp;lt;code&amp;gt;com.openexchange.chronos.storage.rdb.migration.ChronosStorageMigrationTask&amp;lt;/code&amp;gt; has been introduced, that reads all data from the old tables, applies transformations to match the new stack and writes it into the new tables. The approach and upgrade process is described in detail at https://documentation.open-xchange.com/7.10.0/middleware/components/calendar/data_migration.html. Please read that article carefully before continuing. Especially we want to emphasize again the recommendation to test the migration with a copy of your real data to exclude or determine any issues beforehand.&lt;br /&gt;
&lt;br /&gt;
Before executing this update task, OX App Suite v7.10.0 uses the new calendar stack on top of the old database tables through a compatibility layer. As the old storage layout lacks certain functionality, not all features are functional in between the application upgrade and execution of the update task. Due to this fact, a few spots are affected where not all appointment data that the user interface allows to enter can be persisted. This includes:&lt;br /&gt;
&lt;br /&gt;
* Reminders, where still only one notification prior the appointment start is possible&lt;br /&gt;
* Colors, that cannot be mapped to the previously used labels&lt;br /&gt;
* 4-byte UTF-8 characters (emojis) are not yet possible&lt;br /&gt;
* Secret appointments, that are still stored as private ones&lt;br /&gt;
* An appointment's end timezone can't be applied, if it's different from the start timezone&lt;br /&gt;
&lt;br /&gt;
Operators of ''non-Galera'' MySQL setups - i.e. Master-Slave replication - can potentially speed up the migration by configuring &amp;lt;code&amp;gt;com.openexchange.calendar.migration.intermediateCommits = false&amp;lt;/code&amp;gt;. Per default the migration is performed in batches that separately committed, as Galera does not cope well with large transactions. By changing the setting to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, a single transaction with batch-mode enabled is used.&lt;br /&gt;
&lt;br /&gt;
'''Important:''' The migrating of calendar data actually leads to a duplication of that data. Also with OX App Suite v7.10.0 every new calendar data is written to both, the old and the new tables redundantly to preserve to ability to roll back to OX App Suite v7.8.4. However, only the parts can preserved that match the old data model. I.e. additional features like multiple reminders or subscriptions of external calendars (Google Calendar, SchedJoules) cannot be preserved during a rollback.&lt;br /&gt;
&lt;br /&gt;
A repeated OX App Suite v7.10.0 upgrade after a former rollback to OX App Suite v7.8.4 requires to force re-execution of this update task!&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:7_10_Database_Migration&amp;diff=24152</id>
		<title>AppSuite:7 10 Database Migration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:7_10_Database_Migration&amp;diff=24152"/>
		<updated>2018-07-06T08:43:41Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Initial OX App Suite v7.10.0 Rollout */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Version|7.10.0}}&lt;br /&gt;
&lt;br /&gt;
= Database Migration with OX App Suite v7.10.0 =&lt;br /&gt;
&lt;br /&gt;
OX App Suite v7.10.0 introduces significant changes regarding the underlying MySQL database system that require special attention in case of upgrades from former versions. Please read this paper carefully to ensure a smooth and clean upgrade process.&lt;br /&gt;
&lt;br /&gt;
== Change Overview ==&lt;br /&gt;
&lt;br /&gt;
The most significant changes are:&lt;br /&gt;
* New version and configuration requirements.&lt;br /&gt;
* Most VARCHAR columns need to be migrated to utf8mb4 character encoding.&lt;br /&gt;
* A major rewrite of the calendar application requires full data migration.&lt;br /&gt;
&lt;br /&gt;
We strongly recommend to thoroughly plan and test the upgrade procedure. To gain insights about update task runtimes and the expected load, our recommendation is to clone ConfigDB and the biggest UserDB and perform an isolated test upgrade that especially covers the calendar migration and character encoding changes. Update task durations can be significantly longer than with previous upgrades and the migrations might cause noticeable higher I/O load. Also some additional disk space is needed during and after the migrations.&lt;br /&gt;
&lt;br /&gt;
== Database System ==&lt;br /&gt;
&lt;br /&gt;
MySQL Server is supported in versions 5.6 and 5.7 with recent patch levels only and MariaDB Server 10.1 and 10.2 respectively. Support for 5.6/10.1 exists for compatibility reasons and is transitional. We recommend upgrading to 5.7/10.2 as soon as possible. Any database system upgrade must happen before App Suite is upgraded to OX App Suite v7.10.0. Please follow the respective guides of your database vendor carefully.&lt;br /&gt;
&lt;br /&gt;
Different App Suite and database system versions require different configurations of the DBMS, please follow http://oxpedia.org/wiki/index.php?title=My.cnf to have your database configured in a sane way. Especially the following items require some attention with the upgrade to App Suite 7.10.0 and upgrades of the DBMS itself:&lt;br /&gt;
&lt;br /&gt;
* Supported SQL modes are only &amp;lt;code&amp;gt;NO_ENGINE_SUBSTITUTION&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;NO_AUTO_CREATE_USER&amp;lt;/code&amp;gt;. Starting with App Suite 7.10.0, &amp;lt;code&amp;gt;ONLY_FULL_GROUP_BY&amp;lt;/code&amp;gt; is also supported for MySQL 5.7. It is still not with older versions of MySQL or any MariaDB version! To review the current value, use &amp;lt;code&amp;gt;SHOW GLOBAL VARIABLES WHERE Variable_name = 'sql_mode';&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensure that &amp;lt;code&amp;gt;character_set_server&amp;lt;/code&amp;gt; is set to &amp;lt;code&amp;gt;utf8&amp;lt;/code&amp;gt; for App Suite 7.8.x. Again the current global default value can be obtained via &amp;lt;code&amp;gt;SHOW GLOBAL VARIABLES WHERE Variable_name = 'character_set_server';&amp;lt;/code&amp;gt;. With 7.10.0 being fully rolled out, this setting must then be changed to &amp;lt;code&amp;gt;utf8mb4&amp;lt;/code&amp;gt;. If &amp;lt;code&amp;gt;collation_server&amp;lt;/code&amp;gt; is configured explicitly, it must be set to a matching value according to the character set in either case!&lt;br /&gt;
&lt;br /&gt;
Note that App Suite &amp;lt;= 7.8.4 did not support MySQL 5.7/MariaDB 10.2 so far. While we recommend it for 7.10.0, this leaves a lack of definition during the upgrade process. We consider running 7.8.4 on top of MySQL 5.7/MariaDB 10.2 a valid scenario as long as it is transitional during the upgrade phase. Please take our configuration recommendations seriously to mitigate potential user-facing issues as far as possible.&lt;br /&gt;
&lt;br /&gt;
== Upgrade Procedure ==&lt;br /&gt;
&lt;br /&gt;
The upgrade to OX App Suite v7.10.0 can be performed like any other major upgrade before. However, the duration of blocking database update tasks for the mentioned charset and calendar migrations could conflict with customers’ availability demands. Therefore it is possible to decouple these special time- and resource-intensive tasks from the plain version upgrade. In this section a multi-step approach is described that performs the version upgrade before and independently from the migrations. Every step always results in a working system that is ready to serve user traffic. Some functional implications that affect user experience are outlined in the according subsections.&lt;br /&gt;
&lt;br /&gt;
'''Important:''' Even though the first step leads to a basically working OX App Suite v7.10.0 environment, the subsequent steps are not optional but mandatory! Skipping the migrations will leave a few calendar features dysfunctional and can lead to issues with certain SQL queries that use explicit collations for searching and sorting. Running OX App Suite v7.10.0 in production without having all parts of the migration fulfilled is not supported – OX support will request you to complete the migration tasks when reporting issues that are not related to the migration itself. &lt;br /&gt;
&lt;br /&gt;
== Initial OX App Suite v7.10.0 Rollout ==&lt;br /&gt;
If not done so far, upgrade your MySQL installation to a version supported with OX App Suite v7.10.0 but configure it to be compatible with OX App Suite v7.8.x as described in the “Database System” section.&lt;br /&gt;
&lt;br /&gt;
Despite the fact that the two special migrations for calendar and character sets are explicitly skipped, this section assumes that the “Rolling Upgrade with breaking Hazelcast upgrade” is applied as described in http://oxpedia.org/wiki/index.php?title=AppSuite:Running_a_cluster#Updating_a_Cluster. For the application server upgrade, the common guide from http://oxpedia.org/wiki/index.php?title=AppSuite:UpdatingOXPackages can be followed.&lt;br /&gt;
&lt;br /&gt;
Prepare a dedicated App Suite middleware node that will be used to perform the database update tasks. The node must not be serving any user traffic and be prepared with&lt;br /&gt;
&lt;br /&gt;
* OX App Suite v7.10.0 packages&lt;br /&gt;
* Configuration according to the user production nodes&lt;br /&gt;
* The Hazelcast rolling upgrade compatibility package (see http://oxpedia.org/wiki/index.php?title=AppSuite:Running_a_cluster#Rolling_Upgrade_with_breaking_Hazelcast_upgrade)&lt;br /&gt;
* Exclude the update tasks for both mentioned migrations (i.e. calendar and character encoding). See “Update Task Exclusion” for details.&lt;br /&gt;
* Execute update tasks according to your preferred strategy. More on this can be found at http://oxpedia.org/wiki/index.php?title=UpdateTasks.&lt;br /&gt;
&lt;br /&gt;
By default (if using the &amp;quot;runupdate&amp;quot; tool&amp;quot;) update tasks operate on database schemas sequentially, one at a time. All users from all contexts of a given schema are logged out and locked out. Then, DB schema changes are executed. Finally, users are unlocked and able to login again. Schemas typically contain a few thousand users (if our recommended sizing is being followed) and thus executing update tasks means bunches of a few thousand users will be affected sequentially. You will not have a full downtime. For each update task execution process the following statements hold true:&lt;br /&gt;
&lt;br /&gt;
* All users got service for nearly all the time (all the time but the time where their schema is upgraded)&lt;br /&gt;
* For each point in time, nearly all users got service (all but the ones from the currently updated schema)&lt;br /&gt;
* When update tasks are completed, all users will have been affected by one &amp;quot;logout&amp;quot; - &amp;quot;locked out&amp;quot; cycle&lt;br /&gt;
&lt;br /&gt;
After complete and successful update task execution, roll out OX App Suite v7.10.0 to one node after another. After complete rollout, reconfigure MySQL if appropriate as described in the “Database System” section.&lt;br /&gt;
&lt;br /&gt;
=== Update Task Exclusion ===&lt;br /&gt;
&lt;br /&gt;
Add the following lines to &amp;lt;code&amp;gt;/opt/open-xchange/etc/excludedupdatetasks.properties&amp;lt;/code&amp;gt; or remove the leading # character if already included, so that it contains these two lines:&lt;br /&gt;
&lt;br /&gt;
 # Character Encoding Migration&lt;br /&gt;
 com.openexchange.groupware.update.excludedUpdateTasks=groupware.utf8mb4&lt;br /&gt;
 &lt;br /&gt;
 # Calendar Migration&lt;br /&gt;
 com.openexchange.chronos.storage.rdb.migration.ChronosStorageMigrationTask&lt;br /&gt;
&lt;br /&gt;
The first line does not denote one dedicated update task, but a whole list of tasks. To make exclusion more convenient, the concept of update task namespaces has been introduced. All update tasks belonging to the character encoding migration are part of the &amp;lt;code&amp;gt;groupware.utf8mb4&amp;lt;/code&amp;gt; namespace. The denoted property takes care of excluding them all at once. You can list all according tasks with the &amp;lt;code&amp;gt;/opt/open-xchange/sbin/listUpdateTaskNamespaces&amp;lt;/code&amp;gt; tool.&lt;br /&gt;
&lt;br /&gt;
== Character Encoding Migration ==&lt;br /&gt;
&lt;br /&gt;
The default character encoding for Unicode (named character set by MySQL) of MySQL will become &amp;lt;code&amp;gt;utf8mb4&amp;lt;/code&amp;gt; in the near future. MariaDB on Debian Stretch (9) already has an according default configuration set when installing it from distribution packages. So far all VARCHAR columns are supposed to store at max. 3-byte UTF-8 characters due to the nature of MySQL’s utf8 character encoding. This leads to the fact that for example emojis cannot be saved as part of any App Suite entities. In a mixed-mode scenario (App Suite considers MySQL to operate in utf8mb4 mode due to the &amp;lt;code&amp;gt;character_set_server&amp;lt;/code&amp;gt; setting, while columns are specified with utf8 encoding), this leads to issues whenever certain collations during SELECT statements are enforced. To avoid such issues generally and also increase user experience by finally allowing characters from the Unicode astral plane, Open-Xchange has decided to migrate existing data structures to the utf8mb4 character encoding.&lt;br /&gt;
&lt;br /&gt;
This migration can be executed before or after the calendar migration, while it is recommend to execute it before.&lt;br /&gt;
&lt;br /&gt;
The upgrade procedure is basically the same as above in terms executing update tasks, while the server software is already up to date and needs no further upgrades:&lt;br /&gt;
&lt;br /&gt;
* Again prepare one dedicated node that doesn’t serve any user traffic&lt;br /&gt;
* Remove the according namespace property from &amp;lt;code&amp;gt;excludedupdatetasks.properties&amp;lt;/code&amp;gt; again, but still keep the “ChronosStorageMigrationTask”. Afterwards restart the open-xchange daemon.&lt;br /&gt;
* Execute update tasks according to your preferred strategy.&lt;br /&gt;
&lt;br /&gt;
'''Important:''' The update tasks require a lot of tables to be copied and re-created, leading to high I/O and especially sequential read and write operations. For every copied table the needed MySQL disk space doubles during the update task, so ensure enough free space before running the migration.&lt;br /&gt;
&lt;br /&gt;
== Calendar Data Migration ==&lt;br /&gt;
&lt;br /&gt;
The new calendar stack in OX App Suite v7.10.0 comes along with a new data model using its very own tables in MySQL. To preserve users calendar data, an update task &amp;lt;code&amp;gt;com.openexchange.chronos.storage.rdb.migration.ChronosStorageMigrationTask&amp;lt;/code&amp;gt; has been introduced, that reads all data from the old tables, applies transformations to match the new stack and writes it into the new tables. The approach and upgrade process is described in detail at https://documentation.open-xchange.com/7.10.0/middleware/components/calendar/data_migration.html. Please read that article carefully before continuing. Especially we want to emphasize again the recommendation to test the migration with a copy of your real data to exclude or determine any issues beforehand.&lt;br /&gt;
&lt;br /&gt;
Before executing this update task, OX App Suite v7.10.0 uses the new calendar stack on top of the old database tables through a compatibility layer. As the old storage layout lacks certain functionality, not all features are functional in between the application upgrade and execution of the update task. Due to this fact, a few spots are affected where not all appointment data that the user interface allows to enter can be persisted. This includes:&lt;br /&gt;
&lt;br /&gt;
* Reminders, where still only one notification prior the appointment start is possible&lt;br /&gt;
* Colors, that cannot be mapped to the previously used labels&lt;br /&gt;
* 4-byte UTF-8 characters (emojis) are not yet possible&lt;br /&gt;
* Secret appointments, that are still stored as private ones&lt;br /&gt;
* An appointment's end timezone can't be applied, if it's different from the start timezone&lt;br /&gt;
&lt;br /&gt;
Operators of ''non-Galera'' MySQL setups - i.e. Master-Slave replication - can potentially speed up the migration by configuring &amp;lt;code&amp;gt;com.openexchange.calendar.migration.intermediateCommits = false&amp;lt;/code&amp;gt;. Per default the migration is performed in batches that separately committed, as Galera does not cope well with large transactions. By changing the setting to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, a single transaction with batch-mode enabled is used.&lt;br /&gt;
&lt;br /&gt;
'''Important:''' The migrating of calendar data actually leads to a duplication of that data. Also with OX App Suite v7.10.0 every new calendar data is written to both, the old and the new tables redundantly to preserve to ability to roll back to OX App Suite v7.8.4. However, only the parts can preserved that match the old data model. I.e. additional features like multiple reminders or subscriptions of external calendars (Google Calendar, SchedJoules) cannot be preserved during a rollback.&lt;br /&gt;
&lt;br /&gt;
A repeated OX App Suite v7.10.0 upgrade after a former rollback to OX App Suite v7.8.4 requires to force re-execution of this update task!&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24074</id>
		<title>User:Dominik.epple</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24074"/>
		<updated>2018-06-27T12:30:18Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Registering stuff */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Install Guide ==&lt;br /&gt;
&lt;br /&gt;
=== About this document ===&lt;br /&gt;
&lt;br /&gt;
The aim of this document is to improve on the existing quickinstall guides to be more structured, provide a more extensive view on &amp;quot;single node and beyond&amp;quot; topics, follow closer to existing &amp;quot;best practices&amp;quot; (also, but not only security-wise), and point out what needs to be changed in clustered installations.&lt;br /&gt;
&lt;br /&gt;
Most of the commands given in this document thus assume a high level design of &amp;quot;single-node, all-in-one&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This document was created on Debian Stretch (which, as of time of writing, is not even supported yet), but it should work as-is also for jessie. Porting to RHEL/SLES/... is TODO.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
==== System update ====&lt;br /&gt;
&lt;br /&gt;
You want to start on latest patchlevel of your OS:&lt;br /&gt;
&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get dist-upgrade&lt;br /&gt;
 apt-get install less vim pwgen apt-transport-https&lt;br /&gt;
 # or&lt;br /&gt;
 yum update&lt;br /&gt;
 yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm&lt;br /&gt;
 yum install vim less pwgen wget&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
==== Pregenerate passwords ====&lt;br /&gt;
&lt;br /&gt;
This guide shall feature copy-paste ready commands which create installations with no default passwords.&lt;br /&gt;
&lt;br /&gt;
We will pre-generate some passwords which will live as dotfiles in /root.&lt;br /&gt;
&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxmasterpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxadminpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxuserpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbrootpw&lt;br /&gt;
&lt;br /&gt;
==== Prepare database ====&lt;br /&gt;
&lt;br /&gt;
In real-world installations this will probably be multiple galera clusters of a supported flavor and version. For educational purposes a standalone DB on our single-node machine is sufficient.&lt;br /&gt;
&lt;br /&gt;
Even for single-node, don't forget to apply database tuning. See [[My.cnf|our oxpedia article]] for default tunings. Note that typically you need to re-initialize the MySQL datadir after changing InnoDB sizing values, and subsequently start the service:&lt;br /&gt;
&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 service mysql restart&lt;br /&gt;
&lt;br /&gt;
We aim to create secure-by-default documentation, so here we go: Run mysql_secure_installation, and chose every security relevant option, but let the root password empty in this step, as we set it in the next step:&lt;br /&gt;
&lt;br /&gt;
 # leave the root password empty in mysql_secure_installation as we set it in the subsequent step&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
 # now, configure the password from /root/.dbrootpw&lt;br /&gt;
 mysql -e &amp;quot;UPDATE mysql.user SET Password=PASSWORD('$(cat /root/.dbrootpw)') WHERE User='root'; FLUSH PRIVILEGES;&amp;quot;&lt;br /&gt;
 cat &amp;gt;/root/.my.cnf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=$(cat /root/.dbrootpw)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
MySQL 5.7: the aforementioned must be adjusted using&lt;br /&gt;
&lt;br /&gt;
 ALTER USER USER() IDENTIFIED BY 'tiez7EiNgaish0ee';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These credentials also needs to be put in /etc/mysql/debian.cnf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
On multiple db clusters, do it per node analogously. Just be aware the copy-paste command above expects the /root/.dbrootpw file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare OX user ====&lt;br /&gt;
&lt;br /&gt;
While the packages will create the user automatically if it does not exist, we want to prepare the filestore now, and we need the user therefore.&lt;br /&gt;
&lt;br /&gt;
 useradd -r open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You should hard-wire the userid and groupid to the same fixed value. Otherwise, if you want to use a NFS filestore, you'll run into permissions problems, unless you use nfs4/kerberos/idmapd.&lt;br /&gt;
&lt;br /&gt;
 groupadd -r -g 999 open-xchange&lt;br /&gt;
 useradd -r -g 999 -u 999 open-xchange&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare filestore ====&lt;br /&gt;
&lt;br /&gt;
There are several options here.&lt;br /&gt;
&lt;br /&gt;
===== Single-Node: local directory =====&lt;br /&gt;
&lt;br /&gt;
For a single-node installation, you can just prepare a local directory:&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
===== NFS =====&lt;br /&gt;
&lt;br /&gt;
If using NFS:&lt;br /&gt;
&lt;br /&gt;
Setup on the NFS server: &lt;br /&gt;
&lt;br /&gt;
 apt-get install nfs-kernel-server&lt;br /&gt;
 service nfs-kernel-server restart&lt;br /&gt;
&lt;br /&gt;
Configure /etc/exports. This is for traditional ip based access control; krb5 or other security configuration is out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
 echo &amp;quot;/var/opt/filestore 192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)&amp;quot; &amp;gt;&amp;gt; /etc/exports&lt;br /&gt;
 exportfs -a&lt;br /&gt;
&lt;br /&gt;
Clients can then mount using&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 mount -t nfs -o vers=4 nfs-server:/filestore /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
Or using fstab entries like&lt;br /&gt;
&lt;br /&gt;
 nfs-server:/filestore /var/opt/filestore nfs4 defaults 0 0&lt;br /&gt;
&lt;br /&gt;
===== Object Store =====&lt;br /&gt;
&lt;br /&gt;
You can use an object store. For lab environments Ceph is a convenient option. For demo / educational purpuses a &amp;quot;single node Ceph cluster&amp;quot; even co-located on your &amp;quot;single-node machine&amp;quot; is reasonble, but its setup is out of scope of this document. If you want to use this, be prepared to provide information about endpoint, bucket name, access key, secret key.&lt;br /&gt;
&lt;br /&gt;
===== No filestore =====&lt;br /&gt;
&lt;br /&gt;
If you dont want to provide a filestore, you can configure OX later to run without filestore. (Q: do we still need a dummy registerfilestore on a local directory in that event?)&lt;br /&gt;
&lt;br /&gt;
==== Prepare mail system ====&lt;br /&gt;
&lt;br /&gt;
Formally out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
If you need to create a testing dovecot/postfix setup, you can use our [https://gitlab.open-xchange.com/qa/performance/tree/develop/com.openexchange.test.performance.gatling/src/site-preprocess/dovecot performance testing sample config].&lt;br /&gt;
&lt;br /&gt;
=== Install OX software ===&lt;br /&gt;
&lt;br /&gt;
You need an ldb user and password for updates and proprietary repos. If you dont have such a user, you can still install the free components. You'll get a lot of authentication failed warnings however from apt tools unless you deconfigure the closed repos.&lt;br /&gt;
&lt;br /&gt;
 wget http://software.open-xchange.com/oxbuildkey.pub -O - | apt-key add -&lt;br /&gt;
 wget -O/etc/apt/sources.list.d/ox.list http://software.open-xchange.com/products/DebianJessie.list&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/apt/sources.list.d/ox.list&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
 #&lt;br /&gt;
 # or&lt;br /&gt;
 #&lt;br /&gt;
 wget -O /etc/yum.repos.d/ox.repo http://software.open-xchange.com/products/RHEL7.repo&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/yum.repos.d/ox.repo&lt;br /&gt;
 yum install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
*if you want to have separate frontend (apache) and middleware (open-xchange) systems, make sure to install packages which require apache as dependency on the frontend nodes, and packages which require java as a dependency on the middleware nodes. Currently this results in the split&lt;br /&gt;
** Frontend nodes: open-xchange-appsuite&lt;br /&gt;
** Middleware nodes: everything else&lt;br /&gt;
* If you want to use an object store, install the corresponding open-xchange-filestore-xyz package, like open-xchange-filestore-s3&lt;br /&gt;
* For hazelcast session storage, install also open-xchange-sessionstorage-hazelcast&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Install database schemas ===&lt;br /&gt;
&lt;br /&gt;
If the DB runs on localhost and you have root access, you can use&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; -a&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
Create the DB users on all write instances manually. https://oxpedia.org/wiki/index.php?title=Template:OXLoadBalancingClustering_Database#Creating_Open-Xchange_user&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* to 'openexchange'@'%' identified by '$(cat /root/.dbpw)' WITH GRANT OPTION;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Run initconfigdb with some more options:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-user=openexchange --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --configdb-host=configdb-writehost&lt;br /&gt;
&lt;br /&gt;
(initconfigdb needs to be run only once on one cluster node)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initial configuration ===&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/oxinstaller --add-license=YOUR-OX-LICENSE-CODE --servername=oxserver --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --master-pass=&amp;quot;$(cat /root/.oxmasterpw)&amp;quot; --network-listener-host=localhost --servermemory 1024&lt;br /&gt;
&lt;br /&gt;
'''servername''' is more like a ''clustername'' and needs to be the same for all nodes.&lt;br /&gt;
&lt;br /&gt;
'''servermemory''' should be adjusted to reflect the expected number of concurrent active sessions; sizing assumption is 4MB per session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
 --configdb-readhost=...&lt;br /&gt;
 --configdb-writehost=...&lt;br /&gt;
 --imapserver=...&lt;br /&gt;
 --smtpserver=...&lt;br /&gt;
 --mail-login-src=&amp;lt;login|mail|name&amp;gt;&lt;br /&gt;
 --mail-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --transport-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --jkroute=APP1&lt;br /&gt;
 --object-link-hostname=[service DNS name like ox.example.com]&lt;br /&gt;
 --extras-link=[https://ox.example.com/]&lt;br /&gt;
 --name-of-oxcluster=[something unique per cluster, like business-staging; see --servername]&lt;br /&gt;
 --network-listener-host=&amp;lt;localhost|*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oxinstaller needs to be run on each cluster node with identical options besides the jkroute, which must be unique per cluster node and match the corresponding apache option, see below.&lt;br /&gt;
&lt;br /&gt;
In a cluster you also want to configure hazelcast; see [[AppSuite:Running_a_cluster#Configuration]]. Most prominent options are &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.enabled=true&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&amp;lt;reasonable unique group name&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.group.password=&amp;lt;unique password, CHANGE THE SHIPPED DEFAULT PASSWORD!&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static # static is recommended over multicast for robustness&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=... # configure your nodes as a comma-separated list; a bootstrapping subset is acceptable&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=... # pick your subnet;  Wildcards (*) and ranges (-) can be used&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Start the service:&lt;br /&gt;
&lt;br /&gt;
 systemctl restart open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Start the service on every cluster node.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registering stuff ===&lt;br /&gt;
&lt;br /&gt;
Register the &amp;quot;server&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerserver -n oxserver -A oxadminmaster -P &amp;quot;$(cat /root/.oxmasterpw)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
All the register* commands need to be issued only once per cluster, as the effect is to enter corresponding lines in the configdb.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the filestore:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxmasterpw)&amp;quot; -t file:/var/opt/filestore -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
If you chose an object store, the corresponding registerfilestore line reads as follows (Ceph radosgw example):&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxmasterpw)&amp;quot; -t s3://radosgw -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
It requires configuration of the object store in filestore-s3.properties:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.endpoint=http://localhost:7480&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.bucketName=oxbucket&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.region=eu-west-1&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.pathStyleAccess=true&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.accessKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.secretKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.encryption=none&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.signerOverride=S3SignerType&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.chunkSize=5MB&lt;br /&gt;
&lt;br /&gt;
Changing this file needs another&lt;br /&gt;
&lt;br /&gt;
 service open-xchange restart&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the database:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxmasterpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You probably have multiple clusters with read and write URLs. Register them each like first registering the master, subsequently registering the slave URL with the corresponding master ID:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxmasterpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
This command gives as output the id of the registered db master, like&lt;br /&gt;
&lt;br /&gt;
 database 3 registered&lt;br /&gt;
&lt;br /&gt;
Here, the id is 3. Use this id as argument of the -M switch of the next command:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxmasterpw)&amp;quot; -n oxdbr -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m false -M 3&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Configure Apache ===&lt;br /&gt;
&lt;br /&gt;
Create config files /etc/apache2/conf-enabled/proxy_http.conf, /etc/apache2/sites-enabled/000-default.conf by copy-pasting as explained in [[AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0#Configure_services]]&lt;br /&gt;
&lt;br /&gt;
Make sure you are using mpm_event. Apply concurrent connections tuning as described in [[Tune_apache2_for_more_concurrent_connections]].&lt;br /&gt;
&lt;br /&gt;
Configure modules and restart:&lt;br /&gt;
&lt;br /&gt;
 a2enmod proxy proxy_http proxy_balancer expires deflate headers rewrite mime setenvif lbmethod_byrequests&lt;br /&gt;
 systemctl restart apache2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Make sure that each middleware node got its unique server.properties:com.openexchange.server.backendRoute, e.g. APP1, APP2, APP3, etc.&lt;br /&gt;
&lt;br /&gt;
Configure them in the http proxy definitions like&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP3&lt;br /&gt;
&lt;br /&gt;
If you colocate apache on middleware nodes, you might want to minimize cross-node routing, by setting on each node for the local node a loadfactor=50 and for the other nodes a status=+H instead of the loadfactor. E.g. on node ox1:&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP3&lt;br /&gt;
&lt;br /&gt;
However this requires host-specific config files for apache http proxy.&lt;br /&gt;
&lt;br /&gt;
Use touch-appsuite with one identical timestamp on each frontend node.&lt;br /&gt;
&lt;br /&gt;
 timestamp=$(date -u +%Y%m%d.%H%M%S)&lt;br /&gt;
 for node in $all_frontend_nodes; do&lt;br /&gt;
     ssh $node /opt/open-xchange/sbin/touch-appsuite --timestamp=$timestamp&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Provision a  Test User ===&lt;br /&gt;
&lt;br /&gt;
Provision a sample context and user:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/createcontext  -c 1 -A oxadminmaster -P $(cat /root/.oxmasterpw) -N localdomain -u oxadmin -d &amp;quot;Admin User&amp;quot; -g Admin -s User -p $(cat /root/.oxadminpw) -e oxadmin@localdomain -q 100 --access-combination-name groupware_premium&lt;br /&gt;
 /opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P $(cat /root/.oxadminpw) -u testuser -d &amp;quot;Test User&amp;quot; -g Test -s User -p $(cat /root/.oxuserpw) -e testuser@localdomain --access-combination-name groupware_premium&lt;br /&gt;
&lt;br /&gt;
[[Context_Preprovisioning#Sample_Script]] provides an example how to fast-mode provision a huge number of contexts quickly.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24073</id>
		<title>User:Dominik.epple</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24073"/>
		<updated>2018-06-27T12:29:53Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Initial configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Install Guide ==&lt;br /&gt;
&lt;br /&gt;
=== About this document ===&lt;br /&gt;
&lt;br /&gt;
The aim of this document is to improve on the existing quickinstall guides to be more structured, provide a more extensive view on &amp;quot;single node and beyond&amp;quot; topics, follow closer to existing &amp;quot;best practices&amp;quot; (also, but not only security-wise), and point out what needs to be changed in clustered installations.&lt;br /&gt;
&lt;br /&gt;
Most of the commands given in this document thus assume a high level design of &amp;quot;single-node, all-in-one&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This document was created on Debian Stretch (which, as of time of writing, is not even supported yet), but it should work as-is also for jessie. Porting to RHEL/SLES/... is TODO.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
==== System update ====&lt;br /&gt;
&lt;br /&gt;
You want to start on latest patchlevel of your OS:&lt;br /&gt;
&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get dist-upgrade&lt;br /&gt;
 apt-get install less vim pwgen apt-transport-https&lt;br /&gt;
 # or&lt;br /&gt;
 yum update&lt;br /&gt;
 yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm&lt;br /&gt;
 yum install vim less pwgen wget&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
==== Pregenerate passwords ====&lt;br /&gt;
&lt;br /&gt;
This guide shall feature copy-paste ready commands which create installations with no default passwords.&lt;br /&gt;
&lt;br /&gt;
We will pre-generate some passwords which will live as dotfiles in /root.&lt;br /&gt;
&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxmasterpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxadminpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxuserpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbrootpw&lt;br /&gt;
&lt;br /&gt;
==== Prepare database ====&lt;br /&gt;
&lt;br /&gt;
In real-world installations this will probably be multiple galera clusters of a supported flavor and version. For educational purposes a standalone DB on our single-node machine is sufficient.&lt;br /&gt;
&lt;br /&gt;
Even for single-node, don't forget to apply database tuning. See [[My.cnf|our oxpedia article]] for default tunings. Note that typically you need to re-initialize the MySQL datadir after changing InnoDB sizing values, and subsequently start the service:&lt;br /&gt;
&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 service mysql restart&lt;br /&gt;
&lt;br /&gt;
We aim to create secure-by-default documentation, so here we go: Run mysql_secure_installation, and chose every security relevant option, but let the root password empty in this step, as we set it in the next step:&lt;br /&gt;
&lt;br /&gt;
 # leave the root password empty in mysql_secure_installation as we set it in the subsequent step&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
 # now, configure the password from /root/.dbrootpw&lt;br /&gt;
 mysql -e &amp;quot;UPDATE mysql.user SET Password=PASSWORD('$(cat /root/.dbrootpw)') WHERE User='root'; FLUSH PRIVILEGES;&amp;quot;&lt;br /&gt;
 cat &amp;gt;/root/.my.cnf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=$(cat /root/.dbrootpw)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
MySQL 5.7: the aforementioned must be adjusted using&lt;br /&gt;
&lt;br /&gt;
 ALTER USER USER() IDENTIFIED BY 'tiez7EiNgaish0ee';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These credentials also needs to be put in /etc/mysql/debian.cnf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
On multiple db clusters, do it per node analogously. Just be aware the copy-paste command above expects the /root/.dbrootpw file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare OX user ====&lt;br /&gt;
&lt;br /&gt;
While the packages will create the user automatically if it does not exist, we want to prepare the filestore now, and we need the user therefore.&lt;br /&gt;
&lt;br /&gt;
 useradd -r open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You should hard-wire the userid and groupid to the same fixed value. Otherwise, if you want to use a NFS filestore, you'll run into permissions problems, unless you use nfs4/kerberos/idmapd.&lt;br /&gt;
&lt;br /&gt;
 groupadd -r -g 999 open-xchange&lt;br /&gt;
 useradd -r -g 999 -u 999 open-xchange&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare filestore ====&lt;br /&gt;
&lt;br /&gt;
There are several options here.&lt;br /&gt;
&lt;br /&gt;
===== Single-Node: local directory =====&lt;br /&gt;
&lt;br /&gt;
For a single-node installation, you can just prepare a local directory:&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
===== NFS =====&lt;br /&gt;
&lt;br /&gt;
If using NFS:&lt;br /&gt;
&lt;br /&gt;
Setup on the NFS server: &lt;br /&gt;
&lt;br /&gt;
 apt-get install nfs-kernel-server&lt;br /&gt;
 service nfs-kernel-server restart&lt;br /&gt;
&lt;br /&gt;
Configure /etc/exports. This is for traditional ip based access control; krb5 or other security configuration is out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
 echo &amp;quot;/var/opt/filestore 192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)&amp;quot; &amp;gt;&amp;gt; /etc/exports&lt;br /&gt;
 exportfs -a&lt;br /&gt;
&lt;br /&gt;
Clients can then mount using&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 mount -t nfs -o vers=4 nfs-server:/filestore /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
Or using fstab entries like&lt;br /&gt;
&lt;br /&gt;
 nfs-server:/filestore /var/opt/filestore nfs4 defaults 0 0&lt;br /&gt;
&lt;br /&gt;
===== Object Store =====&lt;br /&gt;
&lt;br /&gt;
You can use an object store. For lab environments Ceph is a convenient option. For demo / educational purpuses a &amp;quot;single node Ceph cluster&amp;quot; even co-located on your &amp;quot;single-node machine&amp;quot; is reasonble, but its setup is out of scope of this document. If you want to use this, be prepared to provide information about endpoint, bucket name, access key, secret key.&lt;br /&gt;
&lt;br /&gt;
===== No filestore =====&lt;br /&gt;
&lt;br /&gt;
If you dont want to provide a filestore, you can configure OX later to run without filestore. (Q: do we still need a dummy registerfilestore on a local directory in that event?)&lt;br /&gt;
&lt;br /&gt;
==== Prepare mail system ====&lt;br /&gt;
&lt;br /&gt;
Formally out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
If you need to create a testing dovecot/postfix setup, you can use our [https://gitlab.open-xchange.com/qa/performance/tree/develop/com.openexchange.test.performance.gatling/src/site-preprocess/dovecot performance testing sample config].&lt;br /&gt;
&lt;br /&gt;
=== Install OX software ===&lt;br /&gt;
&lt;br /&gt;
You need an ldb user and password for updates and proprietary repos. If you dont have such a user, you can still install the free components. You'll get a lot of authentication failed warnings however from apt tools unless you deconfigure the closed repos.&lt;br /&gt;
&lt;br /&gt;
 wget http://software.open-xchange.com/oxbuildkey.pub -O - | apt-key add -&lt;br /&gt;
 wget -O/etc/apt/sources.list.d/ox.list http://software.open-xchange.com/products/DebianJessie.list&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/apt/sources.list.d/ox.list&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
 #&lt;br /&gt;
 # or&lt;br /&gt;
 #&lt;br /&gt;
 wget -O /etc/yum.repos.d/ox.repo http://software.open-xchange.com/products/RHEL7.repo&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/yum.repos.d/ox.repo&lt;br /&gt;
 yum install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
*if you want to have separate frontend (apache) and middleware (open-xchange) systems, make sure to install packages which require apache as dependency on the frontend nodes, and packages which require java as a dependency on the middleware nodes. Currently this results in the split&lt;br /&gt;
** Frontend nodes: open-xchange-appsuite&lt;br /&gt;
** Middleware nodes: everything else&lt;br /&gt;
* If you want to use an object store, install the corresponding open-xchange-filestore-xyz package, like open-xchange-filestore-s3&lt;br /&gt;
* For hazelcast session storage, install also open-xchange-sessionstorage-hazelcast&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Install database schemas ===&lt;br /&gt;
&lt;br /&gt;
If the DB runs on localhost and you have root access, you can use&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; -a&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
Create the DB users on all write instances manually. https://oxpedia.org/wiki/index.php?title=Template:OXLoadBalancingClustering_Database#Creating_Open-Xchange_user&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* to 'openexchange'@'%' identified by '$(cat /root/.dbpw)' WITH GRANT OPTION;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Run initconfigdb with some more options:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-user=openexchange --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --configdb-host=configdb-writehost&lt;br /&gt;
&lt;br /&gt;
(initconfigdb needs to be run only once on one cluster node)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initial configuration ===&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/oxinstaller --add-license=YOUR-OX-LICENSE-CODE --servername=oxserver --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --master-pass=&amp;quot;$(cat /root/.oxmasterpw)&amp;quot; --network-listener-host=localhost --servermemory 1024&lt;br /&gt;
&lt;br /&gt;
'''servername''' is more like a ''clustername'' and needs to be the same for all nodes.&lt;br /&gt;
&lt;br /&gt;
'''servermemory''' should be adjusted to reflect the expected number of concurrent active sessions; sizing assumption is 4MB per session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
 --configdb-readhost=...&lt;br /&gt;
 --configdb-writehost=...&lt;br /&gt;
 --imapserver=...&lt;br /&gt;
 --smtpserver=...&lt;br /&gt;
 --mail-login-src=&amp;lt;login|mail|name&amp;gt;&lt;br /&gt;
 --mail-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --transport-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --jkroute=APP1&lt;br /&gt;
 --object-link-hostname=[service DNS name like ox.example.com]&lt;br /&gt;
 --extras-link=[https://ox.example.com/]&lt;br /&gt;
 --name-of-oxcluster=[something unique per cluster, like business-staging; see --servername]&lt;br /&gt;
 --network-listener-host=&amp;lt;localhost|*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oxinstaller needs to be run on each cluster node with identical options besides the jkroute, which must be unique per cluster node and match the corresponding apache option, see below.&lt;br /&gt;
&lt;br /&gt;
In a cluster you also want to configure hazelcast; see [[AppSuite:Running_a_cluster#Configuration]]. Most prominent options are &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.enabled=true&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&amp;lt;reasonable unique group name&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.group.password=&amp;lt;unique password, CHANGE THE SHIPPED DEFAULT PASSWORD!&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static # static is recommended over multicast for robustness&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=... # configure your nodes as a comma-separated list; a bootstrapping subset is acceptable&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=... # pick your subnet;  Wildcards (*) and ranges (-) can be used&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Start the service:&lt;br /&gt;
&lt;br /&gt;
 systemctl restart open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Start the service on every cluster node.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registering stuff ===&lt;br /&gt;
&lt;br /&gt;
Register the &amp;quot;server&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerserver -n oxserver -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
All the register* commands need to be issued only once per cluster, as the effect is to enter corresponding lines in the configdb.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the filestore:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t file:/var/opt/filestore -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
If you chose an object store, the corresponding registerfilestore line reads as follows (Ceph radosgw example):&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t s3://radosgw -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
It requires configuration of the object store in filestore-s3.properties:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.endpoint=http://localhost:7480&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.bucketName=oxbucket&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.region=eu-west-1&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.pathStyleAccess=true&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.accessKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.secretKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.encryption=none&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.signerOverride=S3SignerType&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.chunkSize=5MB&lt;br /&gt;
&lt;br /&gt;
Changing this file needs another&lt;br /&gt;
&lt;br /&gt;
 service open-xchange restart&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the database:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You probably have multiple clusters with read and write URLs. Register them each like first registering the master, subsequently registering the slave URL with the corresponding master ID:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
This command gives as output the id of the registered db master, like&lt;br /&gt;
&lt;br /&gt;
 database 3 registered&lt;br /&gt;
&lt;br /&gt;
Here, the id is 3. Use this id as argument of the -M switch of the next command:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdbr -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m false -M 3&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Configure Apache ===&lt;br /&gt;
&lt;br /&gt;
Create config files /etc/apache2/conf-enabled/proxy_http.conf, /etc/apache2/sites-enabled/000-default.conf by copy-pasting as explained in [[AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0#Configure_services]]&lt;br /&gt;
&lt;br /&gt;
Make sure you are using mpm_event. Apply concurrent connections tuning as described in [[Tune_apache2_for_more_concurrent_connections]].&lt;br /&gt;
&lt;br /&gt;
Configure modules and restart:&lt;br /&gt;
&lt;br /&gt;
 a2enmod proxy proxy_http proxy_balancer expires deflate headers rewrite mime setenvif lbmethod_byrequests&lt;br /&gt;
 systemctl restart apache2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Make sure that each middleware node got its unique server.properties:com.openexchange.server.backendRoute, e.g. APP1, APP2, APP3, etc.&lt;br /&gt;
&lt;br /&gt;
Configure them in the http proxy definitions like&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP3&lt;br /&gt;
&lt;br /&gt;
If you colocate apache on middleware nodes, you might want to minimize cross-node routing, by setting on each node for the local node a loadfactor=50 and for the other nodes a status=+H instead of the loadfactor. E.g. on node ox1:&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP3&lt;br /&gt;
&lt;br /&gt;
However this requires host-specific config files for apache http proxy.&lt;br /&gt;
&lt;br /&gt;
Use touch-appsuite with one identical timestamp on each frontend node.&lt;br /&gt;
&lt;br /&gt;
 timestamp=$(date -u +%Y%m%d.%H%M%S)&lt;br /&gt;
 for node in $all_frontend_nodes; do&lt;br /&gt;
     ssh $node /opt/open-xchange/sbin/touch-appsuite --timestamp=$timestamp&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Provision a  Test User ===&lt;br /&gt;
&lt;br /&gt;
Provision a sample context and user:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/createcontext  -c 1 -A oxadminmaster -P $(cat /root/.oxmasterpw) -N localdomain -u oxadmin -d &amp;quot;Admin User&amp;quot; -g Admin -s User -p $(cat /root/.oxadminpw) -e oxadmin@localdomain -q 100 --access-combination-name groupware_premium&lt;br /&gt;
 /opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P $(cat /root/.oxadminpw) -u testuser -d &amp;quot;Test User&amp;quot; -g Test -s User -p $(cat /root/.oxuserpw) -e testuser@localdomain --access-combination-name groupware_premium&lt;br /&gt;
&lt;br /&gt;
[[Context_Preprovisioning#Sample_Script]] provides an example how to fast-mode provision a huge number of contexts quickly.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24072</id>
		<title>User:Dominik.epple</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24072"/>
		<updated>2018-06-27T12:29:41Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Pregenerate passwords */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Install Guide ==&lt;br /&gt;
&lt;br /&gt;
=== About this document ===&lt;br /&gt;
&lt;br /&gt;
The aim of this document is to improve on the existing quickinstall guides to be more structured, provide a more extensive view on &amp;quot;single node and beyond&amp;quot; topics, follow closer to existing &amp;quot;best practices&amp;quot; (also, but not only security-wise), and point out what needs to be changed in clustered installations.&lt;br /&gt;
&lt;br /&gt;
Most of the commands given in this document thus assume a high level design of &amp;quot;single-node, all-in-one&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This document was created on Debian Stretch (which, as of time of writing, is not even supported yet), but it should work as-is also for jessie. Porting to RHEL/SLES/... is TODO.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
==== System update ====&lt;br /&gt;
&lt;br /&gt;
You want to start on latest patchlevel of your OS:&lt;br /&gt;
&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get dist-upgrade&lt;br /&gt;
 apt-get install less vim pwgen apt-transport-https&lt;br /&gt;
 # or&lt;br /&gt;
 yum update&lt;br /&gt;
 yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm&lt;br /&gt;
 yum install vim less pwgen wget&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
==== Pregenerate passwords ====&lt;br /&gt;
&lt;br /&gt;
This guide shall feature copy-paste ready commands which create installations with no default passwords.&lt;br /&gt;
&lt;br /&gt;
We will pre-generate some passwords which will live as dotfiles in /root.&lt;br /&gt;
&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxmasterpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxadminpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxuserpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbrootpw&lt;br /&gt;
&lt;br /&gt;
==== Prepare database ====&lt;br /&gt;
&lt;br /&gt;
In real-world installations this will probably be multiple galera clusters of a supported flavor and version. For educational purposes a standalone DB on our single-node machine is sufficient.&lt;br /&gt;
&lt;br /&gt;
Even for single-node, don't forget to apply database tuning. See [[My.cnf|our oxpedia article]] for default tunings. Note that typically you need to re-initialize the MySQL datadir after changing InnoDB sizing values, and subsequently start the service:&lt;br /&gt;
&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 service mysql restart&lt;br /&gt;
&lt;br /&gt;
We aim to create secure-by-default documentation, so here we go: Run mysql_secure_installation, and chose every security relevant option, but let the root password empty in this step, as we set it in the next step:&lt;br /&gt;
&lt;br /&gt;
 # leave the root password empty in mysql_secure_installation as we set it in the subsequent step&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
 # now, configure the password from /root/.dbrootpw&lt;br /&gt;
 mysql -e &amp;quot;UPDATE mysql.user SET Password=PASSWORD('$(cat /root/.dbrootpw)') WHERE User='root'; FLUSH PRIVILEGES;&amp;quot;&lt;br /&gt;
 cat &amp;gt;/root/.my.cnf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=$(cat /root/.dbrootpw)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
MySQL 5.7: the aforementioned must be adjusted using&lt;br /&gt;
&lt;br /&gt;
 ALTER USER USER() IDENTIFIED BY 'tiez7EiNgaish0ee';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These credentials also needs to be put in /etc/mysql/debian.cnf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
On multiple db clusters, do it per node analogously. Just be aware the copy-paste command above expects the /root/.dbrootpw file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare OX user ====&lt;br /&gt;
&lt;br /&gt;
While the packages will create the user automatically if it does not exist, we want to prepare the filestore now, and we need the user therefore.&lt;br /&gt;
&lt;br /&gt;
 useradd -r open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You should hard-wire the userid and groupid to the same fixed value. Otherwise, if you want to use a NFS filestore, you'll run into permissions problems, unless you use nfs4/kerberos/idmapd.&lt;br /&gt;
&lt;br /&gt;
 groupadd -r -g 999 open-xchange&lt;br /&gt;
 useradd -r -g 999 -u 999 open-xchange&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare filestore ====&lt;br /&gt;
&lt;br /&gt;
There are several options here.&lt;br /&gt;
&lt;br /&gt;
===== Single-Node: local directory =====&lt;br /&gt;
&lt;br /&gt;
For a single-node installation, you can just prepare a local directory:&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
===== NFS =====&lt;br /&gt;
&lt;br /&gt;
If using NFS:&lt;br /&gt;
&lt;br /&gt;
Setup on the NFS server: &lt;br /&gt;
&lt;br /&gt;
 apt-get install nfs-kernel-server&lt;br /&gt;
 service nfs-kernel-server restart&lt;br /&gt;
&lt;br /&gt;
Configure /etc/exports. This is for traditional ip based access control; krb5 or other security configuration is out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
 echo &amp;quot;/var/opt/filestore 192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)&amp;quot; &amp;gt;&amp;gt; /etc/exports&lt;br /&gt;
 exportfs -a&lt;br /&gt;
&lt;br /&gt;
Clients can then mount using&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 mount -t nfs -o vers=4 nfs-server:/filestore /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
Or using fstab entries like&lt;br /&gt;
&lt;br /&gt;
 nfs-server:/filestore /var/opt/filestore nfs4 defaults 0 0&lt;br /&gt;
&lt;br /&gt;
===== Object Store =====&lt;br /&gt;
&lt;br /&gt;
You can use an object store. For lab environments Ceph is a convenient option. For demo / educational purpuses a &amp;quot;single node Ceph cluster&amp;quot; even co-located on your &amp;quot;single-node machine&amp;quot; is reasonble, but its setup is out of scope of this document. If you want to use this, be prepared to provide information about endpoint, bucket name, access key, secret key.&lt;br /&gt;
&lt;br /&gt;
===== No filestore =====&lt;br /&gt;
&lt;br /&gt;
If you dont want to provide a filestore, you can configure OX later to run without filestore. (Q: do we still need a dummy registerfilestore on a local directory in that event?)&lt;br /&gt;
&lt;br /&gt;
==== Prepare mail system ====&lt;br /&gt;
&lt;br /&gt;
Formally out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
If you need to create a testing dovecot/postfix setup, you can use our [https://gitlab.open-xchange.com/qa/performance/tree/develop/com.openexchange.test.performance.gatling/src/site-preprocess/dovecot performance testing sample config].&lt;br /&gt;
&lt;br /&gt;
=== Install OX software ===&lt;br /&gt;
&lt;br /&gt;
You need an ldb user and password for updates and proprietary repos. If you dont have such a user, you can still install the free components. You'll get a lot of authentication failed warnings however from apt tools unless you deconfigure the closed repos.&lt;br /&gt;
&lt;br /&gt;
 wget http://software.open-xchange.com/oxbuildkey.pub -O - | apt-key add -&lt;br /&gt;
 wget -O/etc/apt/sources.list.d/ox.list http://software.open-xchange.com/products/DebianJessie.list&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/apt/sources.list.d/ox.list&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
 #&lt;br /&gt;
 # or&lt;br /&gt;
 #&lt;br /&gt;
 wget -O /etc/yum.repos.d/ox.repo http://software.open-xchange.com/products/RHEL7.repo&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/yum.repos.d/ox.repo&lt;br /&gt;
 yum install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
*if you want to have separate frontend (apache) and middleware (open-xchange) systems, make sure to install packages which require apache as dependency on the frontend nodes, and packages which require java as a dependency on the middleware nodes. Currently this results in the split&lt;br /&gt;
** Frontend nodes: open-xchange-appsuite&lt;br /&gt;
** Middleware nodes: everything else&lt;br /&gt;
* If you want to use an object store, install the corresponding open-xchange-filestore-xyz package, like open-xchange-filestore-s3&lt;br /&gt;
* For hazelcast session storage, install also open-xchange-sessionstorage-hazelcast&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Install database schemas ===&lt;br /&gt;
&lt;br /&gt;
If the DB runs on localhost and you have root access, you can use&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; -a&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
Create the DB users on all write instances manually. https://oxpedia.org/wiki/index.php?title=Template:OXLoadBalancingClustering_Database#Creating_Open-Xchange_user&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* to 'openexchange'@'%' identified by '$(cat /root/.dbpw)' WITH GRANT OPTION;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Run initconfigdb with some more options:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-user=openexchange --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --configdb-host=configdb-writehost&lt;br /&gt;
&lt;br /&gt;
(initconfigdb needs to be run only once on one cluster node)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initial configuration ===&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/oxinstaller --add-license=YOUR-OX-LICENSE-CODE --servername=oxserver --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --master-pass=&amp;quot;$(cat /root/.oxpw)&amp;quot; --network-listener-host=localhost --servermemory 1024&lt;br /&gt;
&lt;br /&gt;
'''servername''' is more like a ''clustername'' and needs to be the same for all nodes.&lt;br /&gt;
&lt;br /&gt;
'''servermemory''' should be adjusted to reflect the expected number of concurrent active sessions; sizing assumption is 4MB per session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
 --configdb-readhost=...&lt;br /&gt;
 --configdb-writehost=...&lt;br /&gt;
 --imapserver=...&lt;br /&gt;
 --smtpserver=...&lt;br /&gt;
 --mail-login-src=&amp;lt;login|mail|name&amp;gt;&lt;br /&gt;
 --mail-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --transport-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --jkroute=APP1&lt;br /&gt;
 --object-link-hostname=[service DNS name like ox.example.com]&lt;br /&gt;
 --extras-link=[https://ox.example.com/]&lt;br /&gt;
 --name-of-oxcluster=[something unique per cluster, like business-staging; see --servername]&lt;br /&gt;
 --network-listener-host=&amp;lt;localhost|*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oxinstaller needs to be run on each cluster node with identical options besides the jkroute, which must be unique per cluster node and match the corresponding apache option, see below.&lt;br /&gt;
&lt;br /&gt;
In a cluster you also want to configure hazelcast; see [[AppSuite:Running_a_cluster#Configuration]]. Most prominent options are &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.enabled=true&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&amp;lt;reasonable unique group name&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.group.password=&amp;lt;unique password, CHANGE THE SHIPPED DEFAULT PASSWORD!&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static # static is recommended over multicast for robustness&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=... # configure your nodes as a comma-separated list; a bootstrapping subset is acceptable&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=... # pick your subnet;  Wildcards (*) and ranges (-) can be used&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Start the service:&lt;br /&gt;
&lt;br /&gt;
 systemctl restart open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Start the service on every cluster node.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registering stuff ===&lt;br /&gt;
&lt;br /&gt;
Register the &amp;quot;server&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerserver -n oxserver -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
All the register* commands need to be issued only once per cluster, as the effect is to enter corresponding lines in the configdb.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the filestore:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t file:/var/opt/filestore -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
If you chose an object store, the corresponding registerfilestore line reads as follows (Ceph radosgw example):&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t s3://radosgw -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
It requires configuration of the object store in filestore-s3.properties:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.endpoint=http://localhost:7480&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.bucketName=oxbucket&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.region=eu-west-1&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.pathStyleAccess=true&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.accessKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.secretKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.encryption=none&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.signerOverride=S3SignerType&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.chunkSize=5MB&lt;br /&gt;
&lt;br /&gt;
Changing this file needs another&lt;br /&gt;
&lt;br /&gt;
 service open-xchange restart&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the database:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You probably have multiple clusters with read and write URLs. Register them each like first registering the master, subsequently registering the slave URL with the corresponding master ID:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
This command gives as output the id of the registered db master, like&lt;br /&gt;
&lt;br /&gt;
 database 3 registered&lt;br /&gt;
&lt;br /&gt;
Here, the id is 3. Use this id as argument of the -M switch of the next command:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdbr -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m false -M 3&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Configure Apache ===&lt;br /&gt;
&lt;br /&gt;
Create config files /etc/apache2/conf-enabled/proxy_http.conf, /etc/apache2/sites-enabled/000-default.conf by copy-pasting as explained in [[AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0#Configure_services]]&lt;br /&gt;
&lt;br /&gt;
Make sure you are using mpm_event. Apply concurrent connections tuning as described in [[Tune_apache2_for_more_concurrent_connections]].&lt;br /&gt;
&lt;br /&gt;
Configure modules and restart:&lt;br /&gt;
&lt;br /&gt;
 a2enmod proxy proxy_http proxy_balancer expires deflate headers rewrite mime setenvif lbmethod_byrequests&lt;br /&gt;
 systemctl restart apache2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Make sure that each middleware node got its unique server.properties:com.openexchange.server.backendRoute, e.g. APP1, APP2, APP3, etc.&lt;br /&gt;
&lt;br /&gt;
Configure them in the http proxy definitions like&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP3&lt;br /&gt;
&lt;br /&gt;
If you colocate apache on middleware nodes, you might want to minimize cross-node routing, by setting on each node for the local node a loadfactor=50 and for the other nodes a status=+H instead of the loadfactor. E.g. on node ox1:&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP3&lt;br /&gt;
&lt;br /&gt;
However this requires host-specific config files for apache http proxy.&lt;br /&gt;
&lt;br /&gt;
Use touch-appsuite with one identical timestamp on each frontend node.&lt;br /&gt;
&lt;br /&gt;
 timestamp=$(date -u +%Y%m%d.%H%M%S)&lt;br /&gt;
 for node in $all_frontend_nodes; do&lt;br /&gt;
     ssh $node /opt/open-xchange/sbin/touch-appsuite --timestamp=$timestamp&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Provision a  Test User ===&lt;br /&gt;
&lt;br /&gt;
Provision a sample context and user:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/createcontext  -c 1 -A oxadminmaster -P $(cat /root/.oxmasterpw) -N localdomain -u oxadmin -d &amp;quot;Admin User&amp;quot; -g Admin -s User -p $(cat /root/.oxadminpw) -e oxadmin@localdomain -q 100 --access-combination-name groupware_premium&lt;br /&gt;
 /opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P $(cat /root/.oxadminpw) -u testuser -d &amp;quot;Test User&amp;quot; -g Test -s User -p $(cat /root/.oxuserpw) -e testuser@localdomain --access-combination-name groupware_premium&lt;br /&gt;
&lt;br /&gt;
[[Context_Preprovisioning#Sample_Script]] provides an example how to fast-mode provision a huge number of contexts quickly.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24071</id>
		<title>User:Dominik.epple</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24071"/>
		<updated>2018-06-27T12:29:21Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Provision a  Test User */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Install Guide ==&lt;br /&gt;
&lt;br /&gt;
=== About this document ===&lt;br /&gt;
&lt;br /&gt;
The aim of this document is to improve on the existing quickinstall guides to be more structured, provide a more extensive view on &amp;quot;single node and beyond&amp;quot; topics, follow closer to existing &amp;quot;best practices&amp;quot; (also, but not only security-wise), and point out what needs to be changed in clustered installations.&lt;br /&gt;
&lt;br /&gt;
Most of the commands given in this document thus assume a high level design of &amp;quot;single-node, all-in-one&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This document was created on Debian Stretch (which, as of time of writing, is not even supported yet), but it should work as-is also for jessie. Porting to RHEL/SLES/... is TODO.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
==== System update ====&lt;br /&gt;
&lt;br /&gt;
You want to start on latest patchlevel of your OS:&lt;br /&gt;
&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get dist-upgrade&lt;br /&gt;
 apt-get install less vim pwgen apt-transport-https&lt;br /&gt;
 # or&lt;br /&gt;
 yum update&lt;br /&gt;
 yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm&lt;br /&gt;
 yum install vim less pwgen wget&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
==== Pregenerate passwords ====&lt;br /&gt;
&lt;br /&gt;
This guide shall feature copy-paste ready commands which create installations with no default passwords.&lt;br /&gt;
&lt;br /&gt;
We will pre-generate some passwords which will live as dotfiles in /root.&lt;br /&gt;
&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbrootpw&lt;br /&gt;
&lt;br /&gt;
==== Prepare database ====&lt;br /&gt;
&lt;br /&gt;
In real-world installations this will probably be multiple galera clusters of a supported flavor and version. For educational purposes a standalone DB on our single-node machine is sufficient.&lt;br /&gt;
&lt;br /&gt;
Even for single-node, don't forget to apply database tuning. See [[My.cnf|our oxpedia article]] for default tunings. Note that typically you need to re-initialize the MySQL datadir after changing InnoDB sizing values, and subsequently start the service:&lt;br /&gt;
&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 service mysql restart&lt;br /&gt;
&lt;br /&gt;
We aim to create secure-by-default documentation, so here we go: Run mysql_secure_installation, and chose every security relevant option, but let the root password empty in this step, as we set it in the next step:&lt;br /&gt;
&lt;br /&gt;
 # leave the root password empty in mysql_secure_installation as we set it in the subsequent step&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
 # now, configure the password from /root/.dbrootpw&lt;br /&gt;
 mysql -e &amp;quot;UPDATE mysql.user SET Password=PASSWORD('$(cat /root/.dbrootpw)') WHERE User='root'; FLUSH PRIVILEGES;&amp;quot;&lt;br /&gt;
 cat &amp;gt;/root/.my.cnf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=$(cat /root/.dbrootpw)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
MySQL 5.7: the aforementioned must be adjusted using&lt;br /&gt;
&lt;br /&gt;
 ALTER USER USER() IDENTIFIED BY 'tiez7EiNgaish0ee';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These credentials also needs to be put in /etc/mysql/debian.cnf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
On multiple db clusters, do it per node analogously. Just be aware the copy-paste command above expects the /root/.dbrootpw file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare OX user ====&lt;br /&gt;
&lt;br /&gt;
While the packages will create the user automatically if it does not exist, we want to prepare the filestore now, and we need the user therefore.&lt;br /&gt;
&lt;br /&gt;
 useradd -r open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You should hard-wire the userid and groupid to the same fixed value. Otherwise, if you want to use a NFS filestore, you'll run into permissions problems, unless you use nfs4/kerberos/idmapd.&lt;br /&gt;
&lt;br /&gt;
 groupadd -r -g 999 open-xchange&lt;br /&gt;
 useradd -r -g 999 -u 999 open-xchange&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare filestore ====&lt;br /&gt;
&lt;br /&gt;
There are several options here.&lt;br /&gt;
&lt;br /&gt;
===== Single-Node: local directory =====&lt;br /&gt;
&lt;br /&gt;
For a single-node installation, you can just prepare a local directory:&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
===== NFS =====&lt;br /&gt;
&lt;br /&gt;
If using NFS:&lt;br /&gt;
&lt;br /&gt;
Setup on the NFS server: &lt;br /&gt;
&lt;br /&gt;
 apt-get install nfs-kernel-server&lt;br /&gt;
 service nfs-kernel-server restart&lt;br /&gt;
&lt;br /&gt;
Configure /etc/exports. This is for traditional ip based access control; krb5 or other security configuration is out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
 echo &amp;quot;/var/opt/filestore 192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)&amp;quot; &amp;gt;&amp;gt; /etc/exports&lt;br /&gt;
 exportfs -a&lt;br /&gt;
&lt;br /&gt;
Clients can then mount using&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 mount -t nfs -o vers=4 nfs-server:/filestore /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
Or using fstab entries like&lt;br /&gt;
&lt;br /&gt;
 nfs-server:/filestore /var/opt/filestore nfs4 defaults 0 0&lt;br /&gt;
&lt;br /&gt;
===== Object Store =====&lt;br /&gt;
&lt;br /&gt;
You can use an object store. For lab environments Ceph is a convenient option. For demo / educational purpuses a &amp;quot;single node Ceph cluster&amp;quot; even co-located on your &amp;quot;single-node machine&amp;quot; is reasonble, but its setup is out of scope of this document. If you want to use this, be prepared to provide information about endpoint, bucket name, access key, secret key.&lt;br /&gt;
&lt;br /&gt;
===== No filestore =====&lt;br /&gt;
&lt;br /&gt;
If you dont want to provide a filestore, you can configure OX later to run without filestore. (Q: do we still need a dummy registerfilestore on a local directory in that event?)&lt;br /&gt;
&lt;br /&gt;
==== Prepare mail system ====&lt;br /&gt;
&lt;br /&gt;
Formally out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
If you need to create a testing dovecot/postfix setup, you can use our [https://gitlab.open-xchange.com/qa/performance/tree/develop/com.openexchange.test.performance.gatling/src/site-preprocess/dovecot performance testing sample config].&lt;br /&gt;
&lt;br /&gt;
=== Install OX software ===&lt;br /&gt;
&lt;br /&gt;
You need an ldb user and password for updates and proprietary repos. If you dont have such a user, you can still install the free components. You'll get a lot of authentication failed warnings however from apt tools unless you deconfigure the closed repos.&lt;br /&gt;
&lt;br /&gt;
 wget http://software.open-xchange.com/oxbuildkey.pub -O - | apt-key add -&lt;br /&gt;
 wget -O/etc/apt/sources.list.d/ox.list http://software.open-xchange.com/products/DebianJessie.list&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/apt/sources.list.d/ox.list&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
 #&lt;br /&gt;
 # or&lt;br /&gt;
 #&lt;br /&gt;
 wget -O /etc/yum.repos.d/ox.repo http://software.open-xchange.com/products/RHEL7.repo&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/yum.repos.d/ox.repo&lt;br /&gt;
 yum install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
*if you want to have separate frontend (apache) and middleware (open-xchange) systems, make sure to install packages which require apache as dependency on the frontend nodes, and packages which require java as a dependency on the middleware nodes. Currently this results in the split&lt;br /&gt;
** Frontend nodes: open-xchange-appsuite&lt;br /&gt;
** Middleware nodes: everything else&lt;br /&gt;
* If you want to use an object store, install the corresponding open-xchange-filestore-xyz package, like open-xchange-filestore-s3&lt;br /&gt;
* For hazelcast session storage, install also open-xchange-sessionstorage-hazelcast&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Install database schemas ===&lt;br /&gt;
&lt;br /&gt;
If the DB runs on localhost and you have root access, you can use&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; -a&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
Create the DB users on all write instances manually. https://oxpedia.org/wiki/index.php?title=Template:OXLoadBalancingClustering_Database#Creating_Open-Xchange_user&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* to 'openexchange'@'%' identified by '$(cat /root/.dbpw)' WITH GRANT OPTION;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Run initconfigdb with some more options:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-user=openexchange --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --configdb-host=configdb-writehost&lt;br /&gt;
&lt;br /&gt;
(initconfigdb needs to be run only once on one cluster node)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initial configuration ===&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/oxinstaller --add-license=YOUR-OX-LICENSE-CODE --servername=oxserver --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --master-pass=&amp;quot;$(cat /root/.oxpw)&amp;quot; --network-listener-host=localhost --servermemory 1024&lt;br /&gt;
&lt;br /&gt;
'''servername''' is more like a ''clustername'' and needs to be the same for all nodes.&lt;br /&gt;
&lt;br /&gt;
'''servermemory''' should be adjusted to reflect the expected number of concurrent active sessions; sizing assumption is 4MB per session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
 --configdb-readhost=...&lt;br /&gt;
 --configdb-writehost=...&lt;br /&gt;
 --imapserver=...&lt;br /&gt;
 --smtpserver=...&lt;br /&gt;
 --mail-login-src=&amp;lt;login|mail|name&amp;gt;&lt;br /&gt;
 --mail-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --transport-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --jkroute=APP1&lt;br /&gt;
 --object-link-hostname=[service DNS name like ox.example.com]&lt;br /&gt;
 --extras-link=[https://ox.example.com/]&lt;br /&gt;
 --name-of-oxcluster=[something unique per cluster, like business-staging; see --servername]&lt;br /&gt;
 --network-listener-host=&amp;lt;localhost|*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oxinstaller needs to be run on each cluster node with identical options besides the jkroute, which must be unique per cluster node and match the corresponding apache option, see below.&lt;br /&gt;
&lt;br /&gt;
In a cluster you also want to configure hazelcast; see [[AppSuite:Running_a_cluster#Configuration]]. Most prominent options are &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.enabled=true&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&amp;lt;reasonable unique group name&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.group.password=&amp;lt;unique password, CHANGE THE SHIPPED DEFAULT PASSWORD!&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static # static is recommended over multicast for robustness&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=... # configure your nodes as a comma-separated list; a bootstrapping subset is acceptable&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=... # pick your subnet;  Wildcards (*) and ranges (-) can be used&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Start the service:&lt;br /&gt;
&lt;br /&gt;
 systemctl restart open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Start the service on every cluster node.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registering stuff ===&lt;br /&gt;
&lt;br /&gt;
Register the &amp;quot;server&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerserver -n oxserver -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
All the register* commands need to be issued only once per cluster, as the effect is to enter corresponding lines in the configdb.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the filestore:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t file:/var/opt/filestore -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
If you chose an object store, the corresponding registerfilestore line reads as follows (Ceph radosgw example):&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t s3://radosgw -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
It requires configuration of the object store in filestore-s3.properties:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.endpoint=http://localhost:7480&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.bucketName=oxbucket&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.region=eu-west-1&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.pathStyleAccess=true&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.accessKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.secretKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.encryption=none&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.signerOverride=S3SignerType&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.chunkSize=5MB&lt;br /&gt;
&lt;br /&gt;
Changing this file needs another&lt;br /&gt;
&lt;br /&gt;
 service open-xchange restart&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the database:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You probably have multiple clusters with read and write URLs. Register them each like first registering the master, subsequently registering the slave URL with the corresponding master ID:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
This command gives as output the id of the registered db master, like&lt;br /&gt;
&lt;br /&gt;
 database 3 registered&lt;br /&gt;
&lt;br /&gt;
Here, the id is 3. Use this id as argument of the -M switch of the next command:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdbr -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m false -M 3&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Configure Apache ===&lt;br /&gt;
&lt;br /&gt;
Create config files /etc/apache2/conf-enabled/proxy_http.conf, /etc/apache2/sites-enabled/000-default.conf by copy-pasting as explained in [[AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0#Configure_services]]&lt;br /&gt;
&lt;br /&gt;
Make sure you are using mpm_event. Apply concurrent connections tuning as described in [[Tune_apache2_for_more_concurrent_connections]].&lt;br /&gt;
&lt;br /&gt;
Configure modules and restart:&lt;br /&gt;
&lt;br /&gt;
 a2enmod proxy proxy_http proxy_balancer expires deflate headers rewrite mime setenvif lbmethod_byrequests&lt;br /&gt;
 systemctl restart apache2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Make sure that each middleware node got its unique server.properties:com.openexchange.server.backendRoute, e.g. APP1, APP2, APP3, etc.&lt;br /&gt;
&lt;br /&gt;
Configure them in the http proxy definitions like&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP3&lt;br /&gt;
&lt;br /&gt;
If you colocate apache on middleware nodes, you might want to minimize cross-node routing, by setting on each node for the local node a loadfactor=50 and for the other nodes a status=+H instead of the loadfactor. E.g. on node ox1:&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP3&lt;br /&gt;
&lt;br /&gt;
However this requires host-specific config files for apache http proxy.&lt;br /&gt;
&lt;br /&gt;
Use touch-appsuite with one identical timestamp on each frontend node.&lt;br /&gt;
&lt;br /&gt;
 timestamp=$(date -u +%Y%m%d.%H%M%S)&lt;br /&gt;
 for node in $all_frontend_nodes; do&lt;br /&gt;
     ssh $node /opt/open-xchange/sbin/touch-appsuite --timestamp=$timestamp&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Provision a  Test User ===&lt;br /&gt;
&lt;br /&gt;
Provision a sample context and user:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/createcontext  -c 1 -A oxadminmaster -P $(cat /root/.oxmasterpw) -N localdomain -u oxadmin -d &amp;quot;Admin User&amp;quot; -g Admin -s User -p $(cat /root/.oxadminpw) -e oxadmin@localdomain -q 100 --access-combination-name groupware_premium&lt;br /&gt;
 /opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P $(cat /root/.oxadminpw) -u testuser -d &amp;quot;Test User&amp;quot; -g Test -s User -p $(cat /root/.oxuserpw) -e testuser@localdomain --access-combination-name groupware_premium&lt;br /&gt;
&lt;br /&gt;
[[Context_Preprovisioning#Sample_Script]] provides an example how to fast-mode provision a huge number of contexts quickly.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24053</id>
		<title>User:Dominik.epple</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24053"/>
		<updated>2018-06-15T14:09:10Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Install OX software */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Install Guide ==&lt;br /&gt;
&lt;br /&gt;
=== About this document ===&lt;br /&gt;
&lt;br /&gt;
The aim of this document is to improve on the existing quickinstall guides to be more structured, provide a more extensive view on &amp;quot;single node and beyond&amp;quot; topics, follow closer to existing &amp;quot;best practices&amp;quot; (also, but not only security-wise), and point out what needs to be changed in clustered installations.&lt;br /&gt;
&lt;br /&gt;
Most of the commands given in this document thus assume a high level design of &amp;quot;single-node, all-in-one&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This document was created on Debian Stretch (which, as of time of writing, is not even supported yet), but it should work as-is also for jessie. Porting to RHEL/SLES/... is TODO.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
==== System update ====&lt;br /&gt;
&lt;br /&gt;
You want to start on latest patchlevel of your OS:&lt;br /&gt;
&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get dist-upgrade&lt;br /&gt;
 apt-get install less vim pwgen apt-transport-https&lt;br /&gt;
 # or&lt;br /&gt;
 yum update&lt;br /&gt;
 yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm&lt;br /&gt;
 yum install vim less pwgen wget&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
==== Pregenerate passwords ====&lt;br /&gt;
&lt;br /&gt;
This guide shall feature copy-paste ready commands which create installations with no default passwords.&lt;br /&gt;
&lt;br /&gt;
We will pre-generate some passwords which will live as dotfiles in /root.&lt;br /&gt;
&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbrootpw&lt;br /&gt;
&lt;br /&gt;
==== Prepare database ====&lt;br /&gt;
&lt;br /&gt;
In real-world installations this will probably be multiple galera clusters of a supported flavor and version. For educational purposes a standalone DB on our single-node machine is sufficient.&lt;br /&gt;
&lt;br /&gt;
Even for single-node, don't forget to apply database tuning. See [[My.cnf|our oxpedia article]] for default tunings. Note that typically you need to re-initialize the MySQL datadir after changing InnoDB sizing values, and subsequently start the service:&lt;br /&gt;
&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 service mysql restart&lt;br /&gt;
&lt;br /&gt;
We aim to create secure-by-default documentation, so here we go: Run mysql_secure_installation, and chose every security relevant option, but let the root password empty in this step, as we set it in the next step:&lt;br /&gt;
&lt;br /&gt;
 # leave the root password empty in mysql_secure_installation as we set it in the subsequent step&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
 # now, configure the password from /root/.dbrootpw&lt;br /&gt;
 mysql -e &amp;quot;UPDATE mysql.user SET Password=PASSWORD('$(cat /root/.dbrootpw)') WHERE User='root'; FLUSH PRIVILEGES;&amp;quot;&lt;br /&gt;
 cat &amp;gt;/root/.my.cnf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=$(cat /root/.dbrootpw)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
MySQL 5.7: the aforementioned must be adjusted using&lt;br /&gt;
&lt;br /&gt;
 ALTER USER USER() IDENTIFIED BY 'tiez7EiNgaish0ee';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These credentials also needs to be put in /etc/mysql/debian.cnf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
On multiple db clusters, do it per node analogously. Just be aware the copy-paste command above expects the /root/.dbrootpw file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare OX user ====&lt;br /&gt;
&lt;br /&gt;
While the packages will create the user automatically if it does not exist, we want to prepare the filestore now, and we need the user therefore.&lt;br /&gt;
&lt;br /&gt;
 useradd -r open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You should hard-wire the userid and groupid to the same fixed value. Otherwise, if you want to use a NFS filestore, you'll run into permissions problems, unless you use nfs4/kerberos/idmapd.&lt;br /&gt;
&lt;br /&gt;
 groupadd -r -g 999 open-xchange&lt;br /&gt;
 useradd -r -g 999 -u 999 open-xchange&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare filestore ====&lt;br /&gt;
&lt;br /&gt;
There are several options here.&lt;br /&gt;
&lt;br /&gt;
===== Single-Node: local directory =====&lt;br /&gt;
&lt;br /&gt;
For a single-node installation, you can just prepare a local directory:&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
===== NFS =====&lt;br /&gt;
&lt;br /&gt;
If using NFS:&lt;br /&gt;
&lt;br /&gt;
Setup on the NFS server: &lt;br /&gt;
&lt;br /&gt;
 apt-get install nfs-kernel-server&lt;br /&gt;
 service nfs-kernel-server restart&lt;br /&gt;
&lt;br /&gt;
Configure /etc/exports. This is for traditional ip based access control; krb5 or other security configuration is out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
 echo &amp;quot;/var/opt/filestore 192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)&amp;quot; &amp;gt;&amp;gt; /etc/exports&lt;br /&gt;
 exportfs -a&lt;br /&gt;
&lt;br /&gt;
Clients can then mount using&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 mount -t nfs -o vers=4 nfs-server:/filestore /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
Or using fstab entries like&lt;br /&gt;
&lt;br /&gt;
 nfs-server:/filestore /var/opt/filestore nfs4 defaults 0 0&lt;br /&gt;
&lt;br /&gt;
===== Object Store =====&lt;br /&gt;
&lt;br /&gt;
You can use an object store. For lab environments Ceph is a convenient option. For demo / educational purpuses a &amp;quot;single node Ceph cluster&amp;quot; even co-located on your &amp;quot;single-node machine&amp;quot; is reasonble, but its setup is out of scope of this document. If you want to use this, be prepared to provide information about endpoint, bucket name, access key, secret key.&lt;br /&gt;
&lt;br /&gt;
===== No filestore =====&lt;br /&gt;
&lt;br /&gt;
If you dont want to provide a filestore, you can configure OX later to run without filestore. (Q: do we still need a dummy registerfilestore on a local directory in that event?)&lt;br /&gt;
&lt;br /&gt;
==== Prepare mail system ====&lt;br /&gt;
&lt;br /&gt;
Formally out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
If you need to create a testing dovecot/postfix setup, you can use our [https://gitlab.open-xchange.com/qa/performance/tree/develop/com.openexchange.test.performance.gatling/src/site-preprocess/dovecot performance testing sample config].&lt;br /&gt;
&lt;br /&gt;
=== Install OX software ===&lt;br /&gt;
&lt;br /&gt;
You need an ldb user and password for updates and proprietary repos. If you dont have such a user, you can still install the free components. You'll get a lot of authentication failed warnings however from apt tools unless you deconfigure the closed repos.&lt;br /&gt;
&lt;br /&gt;
 wget http://software.open-xchange.com/oxbuildkey.pub -O - | apt-key add -&lt;br /&gt;
 wget -O/etc/apt/sources.list.d/ox.list http://software.open-xchange.com/products/DebianJessie.list&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/apt/sources.list.d/ox.list&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
 #&lt;br /&gt;
 # or&lt;br /&gt;
 #&lt;br /&gt;
 wget -O /etc/yum.repos.d/ox.repo http://software.open-xchange.com/products/RHEL7.repo&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/yum.repos.d/ox.repo&lt;br /&gt;
 yum install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
*if you want to have separate frontend (apache) and middleware (open-xchange) systems, make sure to install packages which require apache as dependency on the frontend nodes, and packages which require java as a dependency on the middleware nodes. Currently this results in the split&lt;br /&gt;
** Frontend nodes: open-xchange-appsuite&lt;br /&gt;
** Middleware nodes: everything else&lt;br /&gt;
* If you want to use an object store, install the corresponding open-xchange-filestore-xyz package, like open-xchange-filestore-s3&lt;br /&gt;
* For hazelcast session storage, install also open-xchange-sessionstorage-hazelcast&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Install database schemas ===&lt;br /&gt;
&lt;br /&gt;
If the DB runs on localhost and you have root access, you can use&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; -a&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
Create the DB users on all write instances manually. https://oxpedia.org/wiki/index.php?title=Template:OXLoadBalancingClustering_Database#Creating_Open-Xchange_user&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* to 'openexchange'@'%' identified by '$(cat /root/.dbpw)' WITH GRANT OPTION;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Run initconfigdb with some more options:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-user=openexchange --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --configdb-host=configdb-writehost&lt;br /&gt;
&lt;br /&gt;
(initconfigdb needs to be run only once on one cluster node)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initial configuration ===&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/oxinstaller --add-license=YOUR-OX-LICENSE-CODE --servername=oxserver --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --master-pass=&amp;quot;$(cat /root/.oxpw)&amp;quot; --network-listener-host=localhost --servermemory 1024&lt;br /&gt;
&lt;br /&gt;
'''servername''' is more like a ''clustername'' and needs to be the same for all nodes.&lt;br /&gt;
&lt;br /&gt;
'''servermemory''' should be adjusted to reflect the expected number of concurrent active sessions; sizing assumption is 4MB per session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
 --configdb-readhost=...&lt;br /&gt;
 --configdb-writehost=...&lt;br /&gt;
 --imapserver=...&lt;br /&gt;
 --smtpserver=...&lt;br /&gt;
 --mail-login-src=&amp;lt;login|mail|name&amp;gt;&lt;br /&gt;
 --mail-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --transport-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --jkroute=APP1&lt;br /&gt;
 --object-link-hostname=[service DNS name like ox.example.com]&lt;br /&gt;
 --extras-link=[https://ox.example.com/]&lt;br /&gt;
 --name-of-oxcluster=[something unique per cluster, like business-staging; see --servername]&lt;br /&gt;
 --network-listener-host=&amp;lt;localhost|*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oxinstaller needs to be run on each cluster node with identical options besides the jkroute, which must be unique per cluster node and match the corresponding apache option, see below.&lt;br /&gt;
&lt;br /&gt;
In a cluster you also want to configure hazelcast; see [[AppSuite:Running_a_cluster#Configuration]]. Most prominent options are &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.enabled=true&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&amp;lt;reasonable unique group name&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.group.password=&amp;lt;unique password, CHANGE THE SHIPPED DEFAULT PASSWORD!&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static # static is recommended over multicast for robustness&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=... # configure your nodes as a comma-separated list; a bootstrapping subset is acceptable&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=... # pick your subnet;  Wildcards (*) and ranges (-) can be used&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Start the service:&lt;br /&gt;
&lt;br /&gt;
 systemctl restart open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Start the service on every cluster node.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registering stuff ===&lt;br /&gt;
&lt;br /&gt;
Register the &amp;quot;server&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerserver -n oxserver -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
All the register* commands need to be issued only once per cluster, as the effect is to enter corresponding lines in the configdb.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the filestore:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t file:/var/opt/filestore -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
If you chose an object store, the corresponding registerfilestore line reads as follows (Ceph radosgw example):&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t s3://radosgw -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
It requires configuration of the object store in filestore-s3.properties:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.endpoint=http://localhost:7480&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.bucketName=oxbucket&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.region=eu-west-1&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.pathStyleAccess=true&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.accessKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.secretKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.encryption=none&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.signerOverride=S3SignerType&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.chunkSize=5MB&lt;br /&gt;
&lt;br /&gt;
Changing this file needs another&lt;br /&gt;
&lt;br /&gt;
 service open-xchange restart&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the database:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You probably have multiple clusters with read and write URLs. Register them each like first registering the master, subsequently registering the slave URL with the corresponding master ID:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
This command gives as output the id of the registered db master, like&lt;br /&gt;
&lt;br /&gt;
 database 3 registered&lt;br /&gt;
&lt;br /&gt;
Here, the id is 3. Use this id as argument of the -M switch of the next command:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdbr -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m false -M 3&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Configure Apache ===&lt;br /&gt;
&lt;br /&gt;
Create config files /etc/apache2/conf-enabled/proxy_http.conf, /etc/apache2/sites-enabled/000-default.conf by copy-pasting as explained in [[AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0#Configure_services]]&lt;br /&gt;
&lt;br /&gt;
Make sure you are using mpm_event. Apply concurrent connections tuning as described in [[Tune_apache2_for_more_concurrent_connections]].&lt;br /&gt;
&lt;br /&gt;
Configure modules and restart:&lt;br /&gt;
&lt;br /&gt;
 a2enmod proxy proxy_http proxy_balancer expires deflate headers rewrite mime setenvif lbmethod_byrequests&lt;br /&gt;
 systemctl restart apache2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Make sure that each middleware node got its unique server.properties:com.openexchange.server.backendRoute, e.g. APP1, APP2, APP3, etc.&lt;br /&gt;
&lt;br /&gt;
Configure them in the http proxy definitions like&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP3&lt;br /&gt;
&lt;br /&gt;
If you colocate apache on middleware nodes, you might want to minimize cross-node routing, by setting on each node for the local node a loadfactor=50 and for the other nodes a status=+H instead of the loadfactor. E.g. on node ox1:&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP3&lt;br /&gt;
&lt;br /&gt;
However this requires host-specific config files for apache http proxy.&lt;br /&gt;
&lt;br /&gt;
Use touch-appsuite with one identical timestamp on each frontend node.&lt;br /&gt;
&lt;br /&gt;
 timestamp=$(date -u +%Y%m%d.%H%M%S)&lt;br /&gt;
 for node in $all_frontend_nodes; do&lt;br /&gt;
     ssh $node /opt/open-xchange/sbin/touch-appsuite --timestamp=$timestamp&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Provision a  Test User ===&lt;br /&gt;
&lt;br /&gt;
Provision a sample context and user:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/createcontext  -c 1 -A oxadminmaster -P secret -N localdomain -u oxadmin -d &amp;quot;Admin User&amp;quot; -g Admin -s User -p secret -e oxadmin@localdomain -q 100 --access-combination-name groupware_premium&lt;br /&gt;
 /opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P secret -u testuser -d &amp;quot;Test User&amp;quot; -g Test -s User -p secret -e testuser@localdomain --access-combination-name groupware_premium&lt;br /&gt;
&lt;br /&gt;
[[Context_Preprovisioning#Sample_Script]] provides an example how to fast-mode provision a huge number of contexts quickly.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24052</id>
		<title>User:Dominik.epple</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24052"/>
		<updated>2018-06-15T14:03:02Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* System update */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Install Guide ==&lt;br /&gt;
&lt;br /&gt;
=== About this document ===&lt;br /&gt;
&lt;br /&gt;
The aim of this document is to improve on the existing quickinstall guides to be more structured, provide a more extensive view on &amp;quot;single node and beyond&amp;quot; topics, follow closer to existing &amp;quot;best practices&amp;quot; (also, but not only security-wise), and point out what needs to be changed in clustered installations.&lt;br /&gt;
&lt;br /&gt;
Most of the commands given in this document thus assume a high level design of &amp;quot;single-node, all-in-one&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This document was created on Debian Stretch (which, as of time of writing, is not even supported yet), but it should work as-is also for jessie. Porting to RHEL/SLES/... is TODO.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
==== System update ====&lt;br /&gt;
&lt;br /&gt;
You want to start on latest patchlevel of your OS:&lt;br /&gt;
&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get dist-upgrade&lt;br /&gt;
 apt-get install less vim pwgen apt-transport-https&lt;br /&gt;
 # or&lt;br /&gt;
 yum update&lt;br /&gt;
 yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm&lt;br /&gt;
 yum install vim less pwgen wget&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
==== Pregenerate passwords ====&lt;br /&gt;
&lt;br /&gt;
This guide shall feature copy-paste ready commands which create installations with no default passwords.&lt;br /&gt;
&lt;br /&gt;
We will pre-generate some passwords which will live as dotfiles in /root.&lt;br /&gt;
&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbrootpw&lt;br /&gt;
&lt;br /&gt;
==== Prepare database ====&lt;br /&gt;
&lt;br /&gt;
In real-world installations this will probably be multiple galera clusters of a supported flavor and version. For educational purposes a standalone DB on our single-node machine is sufficient.&lt;br /&gt;
&lt;br /&gt;
Even for single-node, don't forget to apply database tuning. See [[My.cnf|our oxpedia article]] for default tunings. Note that typically you need to re-initialize the MySQL datadir after changing InnoDB sizing values, and subsequently start the service:&lt;br /&gt;
&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 service mysql restart&lt;br /&gt;
&lt;br /&gt;
We aim to create secure-by-default documentation, so here we go: Run mysql_secure_installation, and chose every security relevant option, but let the root password empty in this step, as we set it in the next step:&lt;br /&gt;
&lt;br /&gt;
 # leave the root password empty in mysql_secure_installation as we set it in the subsequent step&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
 # now, configure the password from /root/.dbrootpw&lt;br /&gt;
 mysql -e &amp;quot;UPDATE mysql.user SET Password=PASSWORD('$(cat /root/.dbrootpw)') WHERE User='root'; FLUSH PRIVILEGES;&amp;quot;&lt;br /&gt;
 cat &amp;gt;/root/.my.cnf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=$(cat /root/.dbrootpw)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
MySQL 5.7: the aforementioned must be adjusted using&lt;br /&gt;
&lt;br /&gt;
 ALTER USER USER() IDENTIFIED BY 'tiez7EiNgaish0ee';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These credentials also needs to be put in /etc/mysql/debian.cnf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
On multiple db clusters, do it per node analogously. Just be aware the copy-paste command above expects the /root/.dbrootpw file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare OX user ====&lt;br /&gt;
&lt;br /&gt;
While the packages will create the user automatically if it does not exist, we want to prepare the filestore now, and we need the user therefore.&lt;br /&gt;
&lt;br /&gt;
 useradd -r open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You should hard-wire the userid and groupid to the same fixed value. Otherwise, if you want to use a NFS filestore, you'll run into permissions problems, unless you use nfs4/kerberos/idmapd.&lt;br /&gt;
&lt;br /&gt;
 groupadd -r -g 999 open-xchange&lt;br /&gt;
 useradd -r -g 999 -u 999 open-xchange&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare filestore ====&lt;br /&gt;
&lt;br /&gt;
There are several options here.&lt;br /&gt;
&lt;br /&gt;
===== Single-Node: local directory =====&lt;br /&gt;
&lt;br /&gt;
For a single-node installation, you can just prepare a local directory:&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
===== NFS =====&lt;br /&gt;
&lt;br /&gt;
If using NFS:&lt;br /&gt;
&lt;br /&gt;
Setup on the NFS server: &lt;br /&gt;
&lt;br /&gt;
 apt-get install nfs-kernel-server&lt;br /&gt;
 service nfs-kernel-server restart&lt;br /&gt;
&lt;br /&gt;
Configure /etc/exports. This is for traditional ip based access control; krb5 or other security configuration is out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
 echo &amp;quot;/var/opt/filestore 192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)&amp;quot; &amp;gt;&amp;gt; /etc/exports&lt;br /&gt;
 exportfs -a&lt;br /&gt;
&lt;br /&gt;
Clients can then mount using&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 mount -t nfs -o vers=4 nfs-server:/filestore /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
Or using fstab entries like&lt;br /&gt;
&lt;br /&gt;
 nfs-server:/filestore /var/opt/filestore nfs4 defaults 0 0&lt;br /&gt;
&lt;br /&gt;
===== Object Store =====&lt;br /&gt;
&lt;br /&gt;
You can use an object store. For lab environments Ceph is a convenient option. For demo / educational purpuses a &amp;quot;single node Ceph cluster&amp;quot; even co-located on your &amp;quot;single-node machine&amp;quot; is reasonble, but its setup is out of scope of this document. If you want to use this, be prepared to provide information about endpoint, bucket name, access key, secret key.&lt;br /&gt;
&lt;br /&gt;
===== No filestore =====&lt;br /&gt;
&lt;br /&gt;
If you dont want to provide a filestore, you can configure OX later to run without filestore. (Q: do we still need a dummy registerfilestore on a local directory in that event?)&lt;br /&gt;
&lt;br /&gt;
==== Prepare mail system ====&lt;br /&gt;
&lt;br /&gt;
Formally out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
If you need to create a testing dovecot/postfix setup, you can use our [https://gitlab.open-xchange.com/qa/performance/tree/develop/com.openexchange.test.performance.gatling/src/site-preprocess/dovecot performance testing sample config].&lt;br /&gt;
&lt;br /&gt;
=== Install OX software ===&lt;br /&gt;
&lt;br /&gt;
You need an ldb user and password for updates and proprietary repos. If you dont have such a user, you can still install the free components. You'll get a lot of authentication failed warnings however from apt tools unless you deconfigure the closed repos.&lt;br /&gt;
&lt;br /&gt;
 wget http://software.open-xchange.com/oxbuildkey.pub -O - | apt-key add -&lt;br /&gt;
 wget -O/etc/apt/sources.list.d/ox.list http://software.open-xchange.com/products/DebianJessie.list&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/apt/sources.list.d/ox.list&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
*if you want to have separate frontend (apache) and middleware (open-xchange) systems, make sure to install packages which require apache as dependency on the frontend nodes, and packages which require java as a dependency on the middleware nodes. Currently this results in the split&lt;br /&gt;
** Frontend nodes: open-xchange-appsuite&lt;br /&gt;
** Middleware nodes: everything else&lt;br /&gt;
* If you want to use an object store, install the corresponding open-xchange-filestore-xyz package, like open-xchange-filestore-s3&lt;br /&gt;
* For hazelcast session storage, install also open-xchange-sessionstorage-hazelcast&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Install database schemas ===&lt;br /&gt;
&lt;br /&gt;
If the DB runs on localhost and you have root access, you can use&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; -a&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
Create the DB users on all write instances manually. https://oxpedia.org/wiki/index.php?title=Template:OXLoadBalancingClustering_Database#Creating_Open-Xchange_user&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* to 'openexchange'@'%' identified by '$(cat /root/.dbpw)' WITH GRANT OPTION;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Run initconfigdb with some more options:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-user=openexchange --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --configdb-host=configdb-writehost&lt;br /&gt;
&lt;br /&gt;
(initconfigdb needs to be run only once on one cluster node)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initial configuration ===&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/oxinstaller --add-license=YOUR-OX-LICENSE-CODE --servername=oxserver --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --master-pass=&amp;quot;$(cat /root/.oxpw)&amp;quot; --network-listener-host=localhost --servermemory 1024&lt;br /&gt;
&lt;br /&gt;
'''servername''' is more like a ''clustername'' and needs to be the same for all nodes.&lt;br /&gt;
&lt;br /&gt;
'''servermemory''' should be adjusted to reflect the expected number of concurrent active sessions; sizing assumption is 4MB per session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
 --configdb-readhost=...&lt;br /&gt;
 --configdb-writehost=...&lt;br /&gt;
 --imapserver=...&lt;br /&gt;
 --smtpserver=...&lt;br /&gt;
 --mail-login-src=&amp;lt;login|mail|name&amp;gt;&lt;br /&gt;
 --mail-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --transport-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --jkroute=APP1&lt;br /&gt;
 --object-link-hostname=[service DNS name like ox.example.com]&lt;br /&gt;
 --extras-link=[https://ox.example.com/]&lt;br /&gt;
 --name-of-oxcluster=[something unique per cluster, like business-staging; see --servername]&lt;br /&gt;
 --network-listener-host=&amp;lt;localhost|*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oxinstaller needs to be run on each cluster node with identical options besides the jkroute, which must be unique per cluster node and match the corresponding apache option, see below.&lt;br /&gt;
&lt;br /&gt;
In a cluster you also want to configure hazelcast; see [[AppSuite:Running_a_cluster#Configuration]]. Most prominent options are &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.enabled=true&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&amp;lt;reasonable unique group name&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.group.password=&amp;lt;unique password, CHANGE THE SHIPPED DEFAULT PASSWORD!&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static # static is recommended over multicast for robustness&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=... # configure your nodes as a comma-separated list; a bootstrapping subset is acceptable&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=... # pick your subnet;  Wildcards (*) and ranges (-) can be used&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Start the service:&lt;br /&gt;
&lt;br /&gt;
 systemctl restart open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Start the service on every cluster node.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registering stuff ===&lt;br /&gt;
&lt;br /&gt;
Register the &amp;quot;server&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerserver -n oxserver -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
All the register* commands need to be issued only once per cluster, as the effect is to enter corresponding lines in the configdb.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the filestore:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t file:/var/opt/filestore -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
If you chose an object store, the corresponding registerfilestore line reads as follows (Ceph radosgw example):&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t s3://radosgw -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
It requires configuration of the object store in filestore-s3.properties:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.endpoint=http://localhost:7480&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.bucketName=oxbucket&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.region=eu-west-1&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.pathStyleAccess=true&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.accessKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.secretKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.encryption=none&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.signerOverride=S3SignerType&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.chunkSize=5MB&lt;br /&gt;
&lt;br /&gt;
Changing this file needs another&lt;br /&gt;
&lt;br /&gt;
 service open-xchange restart&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the database:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You probably have multiple clusters with read and write URLs. Register them each like first registering the master, subsequently registering the slave URL with the corresponding master ID:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
This command gives as output the id of the registered db master, like&lt;br /&gt;
&lt;br /&gt;
 database 3 registered&lt;br /&gt;
&lt;br /&gt;
Here, the id is 3. Use this id as argument of the -M switch of the next command:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdbr -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m false -M 3&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Configure Apache ===&lt;br /&gt;
&lt;br /&gt;
Create config files /etc/apache2/conf-enabled/proxy_http.conf, /etc/apache2/sites-enabled/000-default.conf by copy-pasting as explained in [[AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0#Configure_services]]&lt;br /&gt;
&lt;br /&gt;
Make sure you are using mpm_event. Apply concurrent connections tuning as described in [[Tune_apache2_for_more_concurrent_connections]].&lt;br /&gt;
&lt;br /&gt;
Configure modules and restart:&lt;br /&gt;
&lt;br /&gt;
 a2enmod proxy proxy_http proxy_balancer expires deflate headers rewrite mime setenvif lbmethod_byrequests&lt;br /&gt;
 systemctl restart apache2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Make sure that each middleware node got its unique server.properties:com.openexchange.server.backendRoute, e.g. APP1, APP2, APP3, etc.&lt;br /&gt;
&lt;br /&gt;
Configure them in the http proxy definitions like&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP3&lt;br /&gt;
&lt;br /&gt;
If you colocate apache on middleware nodes, you might want to minimize cross-node routing, by setting on each node for the local node a loadfactor=50 and for the other nodes a status=+H instead of the loadfactor. E.g. on node ox1:&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP3&lt;br /&gt;
&lt;br /&gt;
However this requires host-specific config files for apache http proxy.&lt;br /&gt;
&lt;br /&gt;
Use touch-appsuite with one identical timestamp on each frontend node.&lt;br /&gt;
&lt;br /&gt;
 timestamp=$(date -u +%Y%m%d.%H%M%S)&lt;br /&gt;
 for node in $all_frontend_nodes; do&lt;br /&gt;
     ssh $node /opt/open-xchange/sbin/touch-appsuite --timestamp=$timestamp&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Provision a  Test User ===&lt;br /&gt;
&lt;br /&gt;
Provision a sample context and user:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/createcontext  -c 1 -A oxadminmaster -P secret -N localdomain -u oxadmin -d &amp;quot;Admin User&amp;quot; -g Admin -s User -p secret -e oxadmin@localdomain -q 100 --access-combination-name groupware_premium&lt;br /&gt;
 /opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P secret -u testuser -d &amp;quot;Test User&amp;quot; -g Test -s User -p secret -e testuser@localdomain --access-combination-name groupware_premium&lt;br /&gt;
&lt;br /&gt;
[[Context_Preprovisioning#Sample_Script]] provides an example how to fast-mode provision a huge number of contexts quickly.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Open-Xchange_Installation_Guide_for_CentOS_7&amp;diff=24029</id>
		<title>AppSuite:Open-Xchange Installation Guide for CentOS 7</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Open-Xchange_Installation_Guide_for_CentOS_7&amp;diff=24029"/>
		<updated>2018-06-12T13:14:10Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Version|7.8.0}}&lt;br /&gt;
&lt;br /&gt;
= Open-Xchange App Suite on CentOS7 Linux =&lt;br /&gt;
&lt;br /&gt;
{{QuickInstIntro|release=appsuite}}&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
* Plain installed CentOS7 with latest updates&lt;br /&gt;
* A configured internet connection&lt;br /&gt;
* &amp;lt;code&amp;gt;httpd&amp;lt;/code&amp;gt; - Apache web server&lt;br /&gt;
* &amp;lt;code&amp;gt;vim&amp;lt;/code&amp;gt; is not installed by default on CentOS7. If you want to copy &amp;amp; paste the commands from this article into a shell window, you need to &amp;lt;code&amp;gt;yum install vim&amp;lt;/code&amp;gt; first.&lt;br /&gt;
&lt;br /&gt;
= Database installation =&lt;br /&gt;
&lt;br /&gt;
Please consult our [[OXLoadBalancingClustering_Database#Standalone_database_setup|database installation instructions]] for information on how to install a database on the local system.&lt;br /&gt;
&lt;br /&gt;
Before proceeding, make sure the local machine has got a working MySQL service in one of the supported versions / flavors with the configuration / tunings applied as mentioned on our [[My.cnf|corresponding page]].&lt;br /&gt;
&lt;br /&gt;
{{AddReposRHEL|rhelname=RHEL7|release=appsuite}}&lt;br /&gt;
&lt;br /&gt;
= Updating repositories and installing packages =&lt;br /&gt;
&lt;br /&gt;
It is highly recommended to import the Open-Xchange build key to your package systems trusted keyring in order to make sure only Open-Xchange packages with valid signing are installed on the system. Otherwise you'll encounter warnings about untrusted package sources. To import the Open-Xchange buildkey, please refer to this quick guide: [[Importing_OX_Buildkey#Importing_key_into_apt_based_systems|Importing OX Buildkey]].&lt;br /&gt;
&lt;br /&gt;
The following command starts the download and installation process of all required package for Open-Xchange deployment:&lt;br /&gt;
&lt;br /&gt;
{{OXPackageInstallation|installer=yum|release=appsuite}}&lt;br /&gt;
&lt;br /&gt;
{{OXConfiguration}}&lt;br /&gt;
&lt;br /&gt;
{{oxinstaller|connector=http}}&lt;br /&gt;
&lt;br /&gt;
After initializing the configuration, start the Open-Xchange service by executing:&lt;br /&gt;
&lt;br /&gt;
 $ systemctl start open-xchange&lt;br /&gt;
&lt;br /&gt;
{{OXRegister|globaldb=true}}&lt;br /&gt;
&lt;br /&gt;
= Configure services =&lt;br /&gt;
&lt;br /&gt;
{{ApacheOXModsIntro|connector=http}}&lt;br /&gt;
&lt;br /&gt;
The default installation of the Apache webserver on CentOS provides a welcome screen which is not necessary for server operation, it can be removed by deleting the corresponding configuration file:&lt;br /&gt;
&lt;br /&gt;
 $ rm /etc/httpd/conf.d/welcome.conf&lt;br /&gt;
&lt;br /&gt;
{{Template:ApacheAppSuiteConf|connector=http|connectorConf=/etc/httpd/conf.d/proxy_http.conf|apacheconf=/etc/httpd/conf.d/ox.conf|docroot=/var/www/html|loadmodule=LoadModule proxy_http_module modules/mod_proxy_http.so|syncProxyName=eas_oxcluster}}&lt;br /&gt;
&lt;br /&gt;
After the configuration is done, restart the Apache webserver&lt;br /&gt;
&lt;br /&gt;
 $ systemctl start httpd&lt;br /&gt;
&lt;br /&gt;
== Apache Setting for more concurrent Connections ==&lt;br /&gt;
&lt;br /&gt;
By default apache2 is configured to support 150 concurrent connections. This forces all parallel requests beyond that limit to wait. Especially if, for example, active sync clients maintain a permanent connection for push events to arrive. The following article explains how that can be done&lt;br /&gt;
&lt;br /&gt;
[[Tune_apache2_for_more_concurrent_connections|Apache Setting for more concurrent Connections]]&lt;br /&gt;
&lt;br /&gt;
= Adding services to runlevels =&lt;br /&gt;
&lt;br /&gt;
The new services are now installed and configured, but to make them start up on a server boot, they need to be added to some runlevels:&lt;br /&gt;
&lt;br /&gt;
 $ systemctl enable mariadb&lt;br /&gt;
 $ systemctl enable httpd&lt;br /&gt;
 $ systemctl enable open-xchange&lt;br /&gt;
&lt;br /&gt;
{{ContextUserAndLogs}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: AppSuite]]&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Open-Xchange_Installation_Guide_for_RHEL7&amp;diff=24027</id>
		<title>AppSuite:Open-Xchange Installation Guide for RHEL7</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Open-Xchange_Installation_Guide_for_RHEL7&amp;diff=24027"/>
		<updated>2018-06-12T13:13:40Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Version|7.8.0}}&lt;br /&gt;
&lt;br /&gt;
= Open-Xchange App Suite on RedHat Enterprise Linux 7 =&lt;br /&gt;
&lt;br /&gt;
{{QuickInstIntro|release=appsuite}}&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
* Plain installed RedHat Enterprise Linux 7 with latest updates&lt;br /&gt;
* Valid access to the RedHat Network&lt;br /&gt;
* A configured internet connection&lt;br /&gt;
* &amp;lt;code&amp;gt;vim&amp;lt;/code&amp;gt; is not installed by default on RHEL7. If you want to copy &amp;amp; paste the commands from this article into a shell window, you need to &amp;lt;code&amp;gt;yum install vim&amp;lt;/code&amp;gt; first.&lt;br /&gt;
&lt;br /&gt;
= Database installation =&lt;br /&gt;
&lt;br /&gt;
Please consult our [[OXLoadBalancingClustering_Database#Standalone_database_setup|database installation instructions]] for information on how to install a database on the local system.&lt;br /&gt;
&lt;br /&gt;
Before proceeding, make sure the local machine has got a working MySQL service in one of the supported versions / flavors with the configuration / tunings applied as mentioned on our [[My.cnf|corresponding page]].&lt;br /&gt;
&lt;br /&gt;
= Enabling required RedHat Repositories =&lt;br /&gt;
&lt;br /&gt;
Ensure that your Redhat system is subscribed by e.g. following this article https://access.redhat.com/solutions/253273&lt;br /&gt;
&lt;br /&gt;
{{AddReposRHEL|rhelname=RHEL7|release=appsuite}}&lt;br /&gt;
&lt;br /&gt;
= Updating repositories and installing packages =&lt;br /&gt;
&lt;br /&gt;
Reload the package index. This will download the package descriptions available at the software repositories:&lt;br /&gt;
&lt;br /&gt;
 $ yum update&lt;br /&gt;
&lt;br /&gt;
The following command starts the download and installation process of all required package for Open-Xchange deployment:&lt;br /&gt;
&lt;br /&gt;
{{OXPackageInstallation|installer=yum|release=appsuite}}&lt;br /&gt;
&lt;br /&gt;
{{OXConfiguration}}&lt;br /&gt;
&lt;br /&gt;
{{oxinstaller|connector=http}}&lt;br /&gt;
&lt;br /&gt;
After initializing the configuration, start the Open-Xchange service by executing:&lt;br /&gt;
&lt;br /&gt;
 $ systemctl start open-xchange&lt;br /&gt;
&lt;br /&gt;
{{OXRegister|globaldb=true}}&lt;br /&gt;
&lt;br /&gt;
= Configure services =&lt;br /&gt;
&lt;br /&gt;
{{ApacheOXModsIntro|connector=http}}&lt;br /&gt;
&lt;br /&gt;
The default installation of the Apache webserver on RHEL provides a welcome screen which is not necessary for server operation, it can be removed by deleting the corresponding configuration file:&lt;br /&gt;
&lt;br /&gt;
 $ rm /etc/httpd/conf.d/welcome.conf&lt;br /&gt;
&lt;br /&gt;
{{Template:ApacheAppSuiteConf|connector=http|connectorConf=/etc/httpd/conf.d/proxy_http.conf|apacheconf=/etc/httpd/conf.d/ox.conf|docroot=/var/www/html/|loadmodule=LoadModule proxy_http_module modules/mod_proxy_http.so|syncProxyName=eas_oxcluster}}&lt;br /&gt;
&lt;br /&gt;
After the configuration is done, restart the Apache webserver&lt;br /&gt;
&lt;br /&gt;
 $ systemctl start httpd&lt;br /&gt;
&lt;br /&gt;
== Apache Setting for more concurrent Connections ==&lt;br /&gt;
&lt;br /&gt;
By default apache2 is configured to support 150 concurrent connections. This forces all parallel requests beyond that limit to wait. Especially if, for example, active sync clients maintain a permanent connection for push events to arrive. The following article explains how that can be done&lt;br /&gt;
&lt;br /&gt;
[[Tune_apache2_for_more_concurrent_connections|Apache Setting for more concurrent Connections]]&lt;br /&gt;
&lt;br /&gt;
= Adding services to runlevels =&lt;br /&gt;
&lt;br /&gt;
The new services are now installed and configured, but to make them start up on a server boot, they need to be added to some runlevels:&lt;br /&gt;
&lt;br /&gt;
 $ systemctl enable mariadb&lt;br /&gt;
 $ systemctl enable httpd&lt;br /&gt;
 $ systemctl enable open-xchange&lt;br /&gt;
&lt;br /&gt;
{{ContextUserAndLogs}}&lt;br /&gt;
&lt;br /&gt;
= Installing Open-Xchange Update packages =&lt;br /&gt;
&lt;br /&gt;
Please read [[UpdatingOXPackages]] on how to get access to the latest Open-Xchange packages.&lt;br /&gt;
&lt;br /&gt;
[[Category: AppSuite]]&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0&amp;diff=24024</id>
		<title>AppSuite:Open-Xchange Installation Guide for Debian 8.0</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0&amp;diff=24024"/>
		<updated>2018-06-12T13:13:02Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Version|7.8.0}}&lt;br /&gt;
&lt;br /&gt;
= OX App Suite on Debian GNU/Linux 8.0 =&lt;br /&gt;
&lt;br /&gt;
{{QuickInstIntro|release=appsuite}}&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
* Plain installed Debian GNU/Linux 8.0, no graphical tools required&lt;br /&gt;
* A supported Java Virtual Machine ([http://oxpedia.org/wiki/index.php?title=AppSuite:OX_System_Requirements#Server_Platforms learn more])&lt;br /&gt;
* A working internet connection&lt;br /&gt;
* vim is not installed by default on Debian. If you want to copy &amp;amp; paste the commands from this article into a shell window, you need to &amp;lt;code&amp;gt;apt-get install vim&amp;lt;/code&amp;gt; first.&lt;br /&gt;
&lt;br /&gt;
= Database installation =&lt;br /&gt;
&lt;br /&gt;
Please consult our [[OXLoadBalancingClustering_Database#Standalone_database_setup|database installation instructions]] for information on how to install a database on the local system.&lt;br /&gt;
&lt;br /&gt;
Before proceeding, make sure the local machine has got a working MySQL service in one of the supported versions / flavors with the configuration / tunings applied as mentioned on our [[My.cnf|corresponding page]].&lt;br /&gt;
&lt;br /&gt;
{{AddReposDebian|debname=jessie|debnameox=DebianJessie|release=appsuite}}&lt;br /&gt;
&lt;br /&gt;
= Updating repositories and install packages =&lt;br /&gt;
&lt;br /&gt;
It is highly recommended to import the Open-Xchange build key to your package systems trusted keyring in order to make sure only Open-Xchange packages with valid signing are installed on the system. Otherwise you'll encounter warnings about untrusted package sources. To import the Open-Xchange buildkey, please refer to this quick guide: [[Importing_OX_Buildkey#Importing_key_into_apt_based_systems|Importing OX Buildkey]].&lt;br /&gt;
&lt;br /&gt;
Reload the package index. This will download the package descriptions available at the software repositories and will enable the Open-Xchange repository as a valid source for signed packages:&lt;br /&gt;
&lt;br /&gt;
 $ apt-get update&lt;br /&gt;
&lt;br /&gt;
The following command starts the download and installation process of all required package for Open-Xchange deployment:&lt;br /&gt;
&lt;br /&gt;
{{OXPackageInstallation|installer=apt-get|javavendor=sun|release=appsuite}}&lt;br /&gt;
&lt;br /&gt;
{{OXConfiguration}}&lt;br /&gt;
&lt;br /&gt;
{{oxinstaller|connector=http}}&lt;br /&gt;
&lt;br /&gt;
After initializing the configuration, restart the Open-Xchange Administration service by executing:&lt;br /&gt;
&lt;br /&gt;
 $ systemctl restart open-xchange&lt;br /&gt;
&lt;br /&gt;
{{OXRegister|globaldb=true}}&lt;br /&gt;
&lt;br /&gt;
= Configure services =&lt;br /&gt;
&lt;br /&gt;
{{ApacheOXModsDebian|connector=http|extramods=lbmethod_byrequests}}&lt;br /&gt;
&lt;br /&gt;
{{Template:ApacheAppSuiteConf|connector=http|connectorConf=/etc/apache2/conf-available/proxy_http.conf|apacheconf=/etc/apache2/sites-enabled/000-default.conf|docroot=/var/www/html|loadmodule=|syncProxyName=eas_oxcluster}}&lt;br /&gt;
&lt;br /&gt;
Enable the proxy configuration&lt;br /&gt;
&lt;br /&gt;
 $ a2enconf proxy_http.conf&lt;br /&gt;
&lt;br /&gt;
After the configuration is done, restart the Apache webserver&lt;br /&gt;
&lt;br /&gt;
 $ systemctl restart apache2&lt;br /&gt;
&lt;br /&gt;
== Upgrade from Debian 7 ==&lt;br /&gt;
&lt;br /&gt;
If you updated from Debian 7 to Debian 8 the proxy_http.conf file is still located in the &amp;lt;tt&amp;gt;conf.d&amp;lt;/tt&amp;gt; directory which is not read in Debian 8. So you have to move the file to &amp;lt;tt&amp;gt;conf-available&amp;lt;/tt&amp;gt; and execute &amp;lt;tt&amp;gt;a2enconf proxy_http&amp;lt;/tt&amp;gt; afterwards.&lt;br /&gt;
&lt;br /&gt;
== Apache Setting for more concurrent Connections ==&lt;br /&gt;
&lt;br /&gt;
By default apache2 is configured to support 150 concurrent connections. This forces all parallel requests beyond that limit to wait. Especially if, for example, active sync clients maintain a permanent connection for push events to arrive. The following article explains how that can be done&lt;br /&gt;
&lt;br /&gt;
[[Tune_apache2_for_more_concurrent_connections|Apache Setting for more concurrent Connections]]&lt;br /&gt;
&lt;br /&gt;
{{ContextUserAndLogs}}&lt;br /&gt;
&lt;br /&gt;
[[Category: AppSuite]]&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24017</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24017"/>
		<updated>2018-06-06T14:20:19Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
That tool will ask for the current root password (which is empty by default) and subsequently questions like:&lt;br /&gt;
&lt;br /&gt;
 Change the root password? [Y/n]&lt;br /&gt;
 Remove anonymous users? [Y/n]&lt;br /&gt;
 Disallow root login remotely? [Y/n]&lt;br /&gt;
 Remove test database and access to it? [Y/n]&lt;br /&gt;
 Reload privilege tables now? [Y/n]&lt;br /&gt;
&lt;br /&gt;
You should answer all these questions with &amp;quot;yes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Configure a strong password for the MySQL &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; user.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system. The actual command depends on your OS and on the MySQL flavor.&lt;br /&gt;
&lt;br /&gt;
 systemctl enable mysql.service&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/pre&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Please use a real password.&lt;br /&gt;
* The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly.&lt;br /&gt;
* If using a database on the same host as the middlware (usually done for POCs and demo installations), you need to grant also to the ''localhost'' host.&lt;br /&gt;
* Consult [[AppSuite:DB_user_privileges]] (or ''grep GRANT /opt/open-xchange/sbin/initconfigdb'') for an up-to-date list of required privileges. The following statement was correct as of the time of writing this section.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXPackageInstallation&amp;diff=24015</id>
		<title>Template:OXPackageInstallation</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXPackageInstallation&amp;diff=24015"/>
		<updated>2018-06-05T13:09:56Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#if:{{{release|}}}|&lt;br /&gt;
{{#ifeq:{{{release|}}}|6.22|&lt;br /&gt;
&lt;br /&gt;
If you want to install everything on a single server, just run&lt;br /&gt;
&lt;br /&gt;
 $ {{{installer}}} install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin \&lt;br /&gt;
    open-xchange-gui {{#if:{{{addonpkgs|}}}|{{{addonpkgs}}}|}}&lt;br /&gt;
&lt;br /&gt;
'''Note 1:''' You have to choose between one of the available spamhandler and authentication packages depending on your requirements.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|{{#ifeq:{{{release|}}}|7|&lt;br /&gt;
&lt;br /&gt;
If you want to install everything on a single server, just run&lt;br /&gt;
&lt;br /&gt;
 $ {{{installer}}} install open-xchange open-xchange-authentication-database \&lt;br /&gt;
   open-xchange-ajp open-xchange-admin open-xchange-ui7&lt;br /&gt;
&lt;br /&gt;
'''Note:''' You have to choose between one of the available authentication packages depending on your requirements. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|{{#ifeq:{{{release|}}}|appsuite|&lt;br /&gt;
&lt;br /&gt;
If you want to install everything on a single server, just run&lt;br /&gt;
&lt;br /&gt;
 $ {{{installer}}} install open-xchange open-xchange-authentication-database open-xchange-grizzly \&lt;br /&gt;
   open-xchange-admin open-xchange-appsuite \&lt;br /&gt;
   open-xchange-appsuite-backend open-xchange-appsuite-manifest&lt;br /&gt;
&lt;br /&gt;
'''Note 1:''' You have to choose between one of the available authentication packages depending on your requirements. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}|}}|}}| {{#!:&lt;br /&gt;
&lt;br /&gt;
== Using Meta packages ==&lt;br /&gt;
&lt;br /&gt;
The following Meta packages are available:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;3&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
!style=&amp;quot;width:230px&amp;quot; align=&amp;quot;left&amp;quot; |Name&lt;br /&gt;
!style=&amp;quot;width:230px&amp;quot; align=&amp;quot;left&amp;quot; |Description&lt;br /&gt;
|-&lt;br /&gt;
|open-xchange-meta-admin&lt;br /&gt;
| all provisioning packages&lt;br /&gt;
|-&lt;br /&gt;
|open-xchange-meta-gui&lt;br /&gt;
| all gui packages&lt;br /&gt;
|-&lt;br /&gt;
|open-xchange-meta-messaging&lt;br /&gt;
| the complete messaging packages like unified inbox, twitter, facebook, etc.&lt;br /&gt;
|-&lt;br /&gt;
|open-xchange-meta-mobility&lt;br /&gt;
| OXtender for business mobility&lt;br /&gt;
|-&lt;br /&gt;
|open-xchange-meta-outlook&lt;br /&gt;
| Outlook OXtender Updater&lt;br /&gt;
|-&lt;br /&gt;
|open-xchange-meta-pubsub&lt;br /&gt;
| all publish/subscribe related packages&lt;br /&gt;
|-&lt;br /&gt;
|open-xchange-meta-server&lt;br /&gt;
| the server backend packages&lt;br /&gt;
|-&lt;br /&gt;
|open-xchange-meta-databaseonly&lt;br /&gt;
| all packages needed when open-xchange is only managed via database and not e.g. LDAP&lt;br /&gt;
|-&lt;br /&gt;
|open-xchange-meta-singleserver&lt;br /&gt;
| most of the above&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If you want to install everything on a single server, just run&lt;br /&gt;
&lt;br /&gt;
 $ {{{installer}}} install open-xchange-meta-singleserver \&lt;br /&gt;
    open-xchange-authentication-database open-xchange-spamhandler-default {{#if:{{{addonpkgs|}}}|{{{addonpkgs}}}|}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' You have to choose between one of the available spamhandler and authentication packages depending on your requirements. If you plan to only manage your open-xchange installation via database and do not plan to integrate e.g. with LDAP and [[OXLDAPSync_Guide|OXLDAPSync]], you might also want to install the package open-xchange-meta-databaseonly.''&lt;br /&gt;
&lt;br /&gt;
Of course you can still install the single packages as usual to be able to select a specific set of functionality that you'd like to have, for example:&lt;br /&gt;
&lt;br /&gt;
 $ {{{installer}}} install \&lt;br /&gt;
{{OXPackageInstallation-Server|javavendor={{{javavendor}}}}} \&lt;br /&gt;
{{OXPackageInstallation-GUI}} {{#if:{{{addonpkgs|}}}|{{{addonpkgs}}}|}}&lt;br /&gt;
&lt;br /&gt;
}}}}&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:ContextUserAndLogs&amp;diff=24014</id>
		<title>Template:ContextUserAndLogs</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:ContextUserAndLogs&amp;diff=24014"/>
		<updated>2018-06-05T13:05:14Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Creating contexts and users =&lt;br /&gt;
&lt;br /&gt;
Now as the whole setup is complete and you already should get a login screen when accessing the server with a webbrowser, we have to setup a context and a default user as the last step of this tutorial.&lt;br /&gt;
&lt;br /&gt;
The mapping ''defaultcontext'' will allow you to set this context as the default one of the entire system so that users which will be created within this context can login into Open-Xchange Server without specifying their domain at the login screen. Only one context can be specified as ''defaultcontext''. The ''oxadmin'' user that will be created by this command is the default admin of the created context. This account will gather additional functions that are also described in the administration manual. The ''context id'' parameter must to be unique and numeric, otherwise the server will complain when you try to create a context. New contexts must be created by the ''oxadminmaster'' user, user accounts inside a context are created with the credentials of the contexts ''oxadmin'' account. The ''access-combination-name'' property defines the set of available modules and functions for users of the context.&lt;br /&gt;
&lt;br /&gt;
 $ /opt/open-xchange/sbin/createcontext -A oxadminmaster -P admin_master_password -c 1 \&lt;br /&gt;
 -u oxadmin -d &amp;quot;Context Admin&amp;quot; -g Admin -s User -p admin_password -L defaultcontext \&lt;br /&gt;
 -e oxadmin@example.com -q 1024 --access-combination-name=groupware_standard&lt;br /&gt;
&lt;br /&gt;
To create a user for testing purposes (Make sure the password you use here for the user is the same password as your email account or you will not be able to use the email module until it is set right):&lt;br /&gt;
&lt;br /&gt;
 $ /opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P admin_password -u testuser \&lt;br /&gt;
 -d &amp;quot;Test User&amp;quot; -g Test -s User -p secret -e testuser@example.com \&lt;br /&gt;
 --imaplogin testuser --imapserver 127.0.0.1 --smtpserver 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
Now connect to the server with a webbrowser and login using the credentials testuser / secret.&lt;br /&gt;
&lt;br /&gt;
A complete overview about the different parameter is provided at  the [[OX_Permission_Level|permission matrix]]&lt;br /&gt;
&lt;br /&gt;
If you need to migrate a batch of users and contexts at once, check the CSV Batch Import documentation [[Csv_import|page]].&lt;br /&gt;
&lt;br /&gt;
= Log files and issue tracking =&lt;br /&gt;
== Default logging mechanism ==&lt;br /&gt;
Whenever unexpected or erroneous behavior takes place, it will be logged depending on the configured loglevel. All logfiles are stored at the operating systems default location. Events triggered by the Open-Xchange Groupware services are logged to a rotating file ''open-xchange.log'', events triggered by the Open-Xchange Administration service are logged to ''open-xchange-admin.log''. Those files are the very first place to monitor.&lt;br /&gt;
 &lt;br /&gt;
 $ tail -f -n200 /var/log/open-xchange/open-xchange.log.0&lt;br /&gt;
&lt;br /&gt;
== Alternative logging mechanisms ==&lt;br /&gt;
Apart from the default file logging mechanism, Open-Xchange supports logging via logback framework and therefore via syslog and/or logstash. This makes it possible to directly log to a local or remote syslog daemon or other services. Logback is highly customizable, please see the documentation below.&lt;br /&gt;
&lt;br /&gt;
* [[AppSuite:OX_Logging|Logback configuration Guide OX App Suite]]&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXConfiguration&amp;diff=24013</id>
		<title>Template:OXConfiguration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXConfiguration&amp;diff=24013"/>
		<updated>2018-06-05T12:49:52Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Open-Xchange configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Open-Xchange configuration =&lt;br /&gt;
&lt;br /&gt;
To avoid confusion right at the start notice that Open-Xchange uses multiple administration levels and requires different credentials at some stages at the installation and server management. Note that the passwords chosen at this guide are weak and should be replaced by stronger passwords.&lt;br /&gt;
* The MySQL database user&lt;br /&gt;
** Username: openexchange&lt;br /&gt;
** Password used at this guide: db_password&lt;br /&gt;
** Responsibility: Execute all kinds of database operations&lt;br /&gt;
&lt;br /&gt;
* The Open-Xchange Admin Master&lt;br /&gt;
** Username: oxadminmaster&lt;br /&gt;
** Password used at this guide: admin_master_password&lt;br /&gt;
** Responsibility: Manage contexts, manage all kinds of low level server configuration&lt;br /&gt;
&lt;br /&gt;
* The Context Admin&lt;br /&gt;
** Username: oxadmin&lt;br /&gt;
** Password used at this guide: admin_password&lt;br /&gt;
** Responsibility: Manage users/groups/resources inside a context&lt;br /&gt;
&lt;br /&gt;
As stated above we assume the MySQL service has been installed previously, and it is running and available.&lt;br /&gt;
&lt;br /&gt;
A good idea is to add the Open-Xchange binaries to PATH:&lt;br /&gt;
&lt;br /&gt;
 $  echo PATH=$PATH:/opt/open-xchange/sbin/ &amp;gt;&amp;gt; ~/.bashrc &amp;amp;&amp;amp; . ~/.bashrc&lt;br /&gt;
&lt;br /&gt;
Now we have to initialize the Open-Xchange ''configdb'' database. This can all be done by executing the ''initconfigdb'' script.&lt;br /&gt;
&lt;br /&gt;
 $ /opt/open-xchange/sbin/initconfigdb --configdb-pass=db_password -a --mysql-root-passwd=root_password&lt;br /&gt;
&lt;br /&gt;
Use the ''--mysql-root-passwd'' option to supply the MySQL root password as configured during database installation.&lt;br /&gt;
&lt;br /&gt;
Add the ''-i'' option if you want to remove an already existing open-xchange configdb.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The -a parameter adds an ''openexchange'' account to MySQL. This account will be used for database connections from the OX App Suite middleware and requires [[AppSuite:DB_user_privileges|some privileges]]. You can also create that account manually [[OXLoadBalancingClustering_Database#Creating_Open-Xchange_user|during database installation / configuration]], in which case you can (should) skip the ''-a'' parameter here.&lt;br /&gt;
&lt;br /&gt;
Before starting any service, all basic configuration files need to be set up correctly. The ''--configdb-pass'' option indicates the password of the ''openexchange'' database user previously created, the ''--master-pass'' options specifies the password of the Open-Xchange ''adminmaster'' user that will be created when executing the ''oxinstaller'' script.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24012</id>
		<title>User:Dominik.epple</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=24012"/>
		<updated>2018-06-05T12:49:28Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Install Guide ==&lt;br /&gt;
&lt;br /&gt;
=== About this document ===&lt;br /&gt;
&lt;br /&gt;
The aim of this document is to improve on the existing quickinstall guides to be more structured, provide a more extensive view on &amp;quot;single node and beyond&amp;quot; topics, follow closer to existing &amp;quot;best practices&amp;quot; (also, but not only security-wise), and point out what needs to be changed in clustered installations.&lt;br /&gt;
&lt;br /&gt;
Most of the commands given in this document thus assume a high level design of &amp;quot;single-node, all-in-one&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This document was created on Debian Stretch (which, as of time of writing, is not even supported yet), but it should work as-is also for jessie. Porting to RHEL/SLES/... is TODO.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
==== System update ====&lt;br /&gt;
&lt;br /&gt;
You want to start on latest patchlevel of your OS:&lt;br /&gt;
&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get dist-upgrade&lt;br /&gt;
 apt-get install less vim pwgen apt-transport-https&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
==== Pregenerate passwords ====&lt;br /&gt;
&lt;br /&gt;
This guide shall feature copy-paste ready commands which create installations with no default passwords.&lt;br /&gt;
&lt;br /&gt;
We will pre-generate some passwords which will live as dotfiles in /root.&lt;br /&gt;
&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbrootpw&lt;br /&gt;
&lt;br /&gt;
==== Prepare database ====&lt;br /&gt;
&lt;br /&gt;
In real-world installations this will probably be multiple galera clusters of a supported flavor and version. For educational purposes a standalone DB on our single-node machine is sufficient.&lt;br /&gt;
&lt;br /&gt;
Even for single-node, don't forget to apply database tuning. See [[My.cnf|our oxpedia article]] for default tunings. Note that typically you need to re-initialize the MySQL datadir after changing InnoDB sizing values, and subsequently start the service:&lt;br /&gt;
&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 service mysql restart&lt;br /&gt;
&lt;br /&gt;
We aim to create secure-by-default documentation, so here we go: Run mysql_secure_installation, and chose every security relevant option, but let the root password empty in this step, as we set it in the next step:&lt;br /&gt;
&lt;br /&gt;
 # leave the root password empty in mysql_secure_installation as we set it in the subsequent step&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
 # now, configure the password from /root/.dbrootpw&lt;br /&gt;
 mysql -e &amp;quot;UPDATE mysql.user SET Password=PASSWORD('$(cat /root/.dbrootpw)') WHERE User='root'; FLUSH PRIVILEGES;&amp;quot;&lt;br /&gt;
 cat &amp;gt;/root/.my.cnf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=$(cat /root/.dbrootpw)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
MySQL 5.7: the aforementioned must be adjusted using&lt;br /&gt;
&lt;br /&gt;
 ALTER USER USER() IDENTIFIED BY 'tiez7EiNgaish0ee';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These credentials also needs to be put in /etc/mysql/debian.cnf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
On multiple db clusters, do it per node analogously. Just be aware the copy-paste command above expects the /root/.dbrootpw file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare OX user ====&lt;br /&gt;
&lt;br /&gt;
While the packages will create the user automatically if it does not exist, we want to prepare the filestore now, and we need the user therefore.&lt;br /&gt;
&lt;br /&gt;
 useradd -r open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You should hard-wire the userid and groupid to the same fixed value. Otherwise, if you want to use a NFS filestore, you'll run into permissions problems, unless you use nfs4/kerberos/idmapd.&lt;br /&gt;
&lt;br /&gt;
 groupadd -r -g 999 open-xchange&lt;br /&gt;
 useradd -r -g 999 -u 999 open-xchange&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare filestore ====&lt;br /&gt;
&lt;br /&gt;
There are several options here.&lt;br /&gt;
&lt;br /&gt;
===== Single-Node: local directory =====&lt;br /&gt;
&lt;br /&gt;
For a single-node installation, you can just prepare a local directory:&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
===== NFS =====&lt;br /&gt;
&lt;br /&gt;
If using NFS:&lt;br /&gt;
&lt;br /&gt;
Setup on the NFS server: &lt;br /&gt;
&lt;br /&gt;
 apt-get install nfs-kernel-server&lt;br /&gt;
 service nfs-kernel-server restart&lt;br /&gt;
&lt;br /&gt;
Configure /etc/exports. This is for traditional ip based access control; krb5 or other security configuration is out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
 echo &amp;quot;/var/opt/filestore 192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)&amp;quot; &amp;gt;&amp;gt; /etc/exports&lt;br /&gt;
 exportfs -a&lt;br /&gt;
&lt;br /&gt;
Clients can then mount using&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 mount -t nfs -o vers=4 nfs-server:/filestore /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
Or using fstab entries like&lt;br /&gt;
&lt;br /&gt;
 nfs-server:/filestore /var/opt/filestore nfs4 defaults 0 0&lt;br /&gt;
&lt;br /&gt;
===== Object Store =====&lt;br /&gt;
&lt;br /&gt;
You can use an object store. For lab environments Ceph is a convenient option. For demo / educational purpuses a &amp;quot;single node Ceph cluster&amp;quot; even co-located on your &amp;quot;single-node machine&amp;quot; is reasonble, but its setup is out of scope of this document. If you want to use this, be prepared to provide information about endpoint, bucket name, access key, secret key.&lt;br /&gt;
&lt;br /&gt;
===== No filestore =====&lt;br /&gt;
&lt;br /&gt;
If you dont want to provide a filestore, you can configure OX later to run without filestore. (Q: do we still need a dummy registerfilestore on a local directory in that event?)&lt;br /&gt;
&lt;br /&gt;
==== Prepare mail system ====&lt;br /&gt;
&lt;br /&gt;
Formally out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
If you need to create a testing dovecot/postfix setup, you can use our [https://gitlab.open-xchange.com/qa/performance/tree/develop/com.openexchange.test.performance.gatling/src/site-preprocess/dovecot performance testing sample config].&lt;br /&gt;
&lt;br /&gt;
=== Install OX software ===&lt;br /&gt;
&lt;br /&gt;
You need an ldb user and password for updates and proprietary repos. If you dont have such a user, you can still install the free components. You'll get a lot of authentication failed warnings however from apt tools unless you deconfigure the closed repos.&lt;br /&gt;
&lt;br /&gt;
 wget http://software.open-xchange.com/oxbuildkey.pub -O - | apt-key add -&lt;br /&gt;
 wget -O/etc/apt/sources.list.d/ox.list http://software.open-xchange.com/products/DebianJessie.list&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/apt/sources.list.d/ox.list&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
*if you want to have separate frontend (apache) and middleware (open-xchange) systems, make sure to install packages which require apache as dependency on the frontend nodes, and packages which require java as a dependency on the middleware nodes. Currently this results in the split&lt;br /&gt;
** Frontend nodes: open-xchange-appsuite&lt;br /&gt;
** Middleware nodes: everything else&lt;br /&gt;
* If you want to use an object store, install the corresponding open-xchange-filestore-xyz package, like open-xchange-filestore-s3&lt;br /&gt;
* For hazelcast session storage, install also open-xchange-sessionstorage-hazelcast&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Install database schemas ===&lt;br /&gt;
&lt;br /&gt;
If the DB runs on localhost and you have root access, you can use&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; -a&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
Create the DB users on all write instances manually. https://oxpedia.org/wiki/index.php?title=Template:OXLoadBalancingClustering_Database#Creating_Open-Xchange_user&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* to 'openexchange'@'%' identified by '$(cat /root/.dbpw)' WITH GRANT OPTION;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Run initconfigdb with some more options:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-user=openexchange --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --configdb-host=configdb-writehost&lt;br /&gt;
&lt;br /&gt;
(initconfigdb needs to be run only once on one cluster node)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initial configuration ===&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/oxinstaller --add-license=YOUR-OX-LICENSE-CODE --servername=oxserver --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --master-pass=&amp;quot;$(cat /root/.oxpw)&amp;quot; --network-listener-host=localhost --servermemory 1024&lt;br /&gt;
&lt;br /&gt;
'''servername''' is more like a ''clustername'' and needs to be the same for all nodes.&lt;br /&gt;
&lt;br /&gt;
'''servermemory''' should be adjusted to reflect the expected number of concurrent active sessions; sizing assumption is 4MB per session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
 --configdb-readhost=...&lt;br /&gt;
 --configdb-writehost=...&lt;br /&gt;
 --imapserver=...&lt;br /&gt;
 --smtpserver=...&lt;br /&gt;
 --mail-login-src=&amp;lt;login|mail|name&amp;gt;&lt;br /&gt;
 --mail-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --transport-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --jkroute=APP1&lt;br /&gt;
 --object-link-hostname=[service DNS name like ox.example.com]&lt;br /&gt;
 --extras-link=[https://ox.example.com/]&lt;br /&gt;
 --name-of-oxcluster=[something unique per cluster, like business-staging; see --servername]&lt;br /&gt;
 --network-listener-host=&amp;lt;localhost|*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oxinstaller needs to be run on each cluster node with identical options besides the jkroute, which must be unique per cluster node and match the corresponding apache option, see below.&lt;br /&gt;
&lt;br /&gt;
In a cluster you also want to configure hazelcast; see [[AppSuite:Running_a_cluster#Configuration]]. Most prominent options are &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.enabled=true&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&amp;lt;reasonable unique group name&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.group.password=&amp;lt;unique password, CHANGE THE SHIPPED DEFAULT PASSWORD!&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static # static is recommended over multicast for robustness&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=... # configure your nodes as a comma-separated list; a bootstrapping subset is acceptable&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=... # pick your subnet;  Wildcards (*) and ranges (-) can be used&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Start the service:&lt;br /&gt;
&lt;br /&gt;
 systemctl restart open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Start the service on every cluster node.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registering stuff ===&lt;br /&gt;
&lt;br /&gt;
Register the &amp;quot;server&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerserver -n oxserver -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
All the register* commands need to be issued only once per cluster, as the effect is to enter corresponding lines in the configdb.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the filestore:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t file:/var/opt/filestore -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
If you chose an object store, the corresponding registerfilestore line reads as follows (Ceph radosgw example):&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t s3://radosgw -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
It requires configuration of the object store in filestore-s3.properties:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.endpoint=http://localhost:7480&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.bucketName=oxbucket&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.region=eu-west-1&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.pathStyleAccess=true&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.accessKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.secretKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.encryption=none&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.signerOverride=S3SignerType&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.chunkSize=5MB&lt;br /&gt;
&lt;br /&gt;
Changing this file needs another&lt;br /&gt;
&lt;br /&gt;
 service open-xchange restart&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the database:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You probably have multiple clusters with read and write URLs. Register them each like first registering the master, subsequently registering the slave URL with the corresponding master ID:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
This command gives as output the id of the registered db master, like&lt;br /&gt;
&lt;br /&gt;
 database 3 registered&lt;br /&gt;
&lt;br /&gt;
Here, the id is 3. Use this id as argument of the -M switch of the next command:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdbr -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m false -M 3&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Configure Apache ===&lt;br /&gt;
&lt;br /&gt;
Create config files /etc/apache2/conf-enabled/proxy_http.conf, /etc/apache2/sites-enabled/000-default.conf by copy-pasting as explained in [[AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0#Configure_services]]&lt;br /&gt;
&lt;br /&gt;
Make sure you are using mpm_event. Apply concurrent connections tuning as described in [[Tune_apache2_for_more_concurrent_connections]].&lt;br /&gt;
&lt;br /&gt;
Configure modules and restart:&lt;br /&gt;
&lt;br /&gt;
 a2enmod proxy proxy_http proxy_balancer expires deflate headers rewrite mime setenvif lbmethod_byrequests&lt;br /&gt;
 systemctl restart apache2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Make sure that each middleware node got its unique server.properties:com.openexchange.server.backendRoute, e.g. APP1, APP2, APP3, etc.&lt;br /&gt;
&lt;br /&gt;
Configure them in the http proxy definitions like&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP3&lt;br /&gt;
&lt;br /&gt;
If you colocate apache on middleware nodes, you might want to minimize cross-node routing, by setting on each node for the local node a loadfactor=50 and for the other nodes a status=+H instead of the loadfactor. E.g. on node ox1:&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP3&lt;br /&gt;
&lt;br /&gt;
However this requires host-specific config files for apache http proxy.&lt;br /&gt;
&lt;br /&gt;
Use touch-appsuite with one identical timestamp on each frontend node.&lt;br /&gt;
&lt;br /&gt;
 timestamp=$(date -u +%Y%m%d.%H%M%S)&lt;br /&gt;
 for node in $all_frontend_nodes; do&lt;br /&gt;
     ssh $node /opt/open-xchange/sbin/touch-appsuite --timestamp=$timestamp&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Provision a  Test User ===&lt;br /&gt;
&lt;br /&gt;
Provision a sample context and user:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/createcontext  -c 1 -A oxadminmaster -P secret -N localdomain -u oxadmin -d &amp;quot;Admin User&amp;quot; -g Admin -s User -p secret -e oxadmin@localdomain -q 100 --access-combination-name groupware_premium&lt;br /&gt;
 /opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P secret -u testuser -d &amp;quot;Test User&amp;quot; -g Test -s User -p secret -e testuser@localdomain --access-combination-name groupware_premium&lt;br /&gt;
&lt;br /&gt;
[[Context_Preprovisioning#Sample_Script]] provides an example how to fast-mode provision a huge number of contexts quickly.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24011</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24011"/>
		<updated>2018-06-05T12:47:36Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Creating Open-Xchange user */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service, and run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/pre&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Please use a real password.&lt;br /&gt;
* The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly.&lt;br /&gt;
* If using a database on the same host as the middlware (usually done for POCs and demo installations), you need to grant also to the ''localhost'' host.&lt;br /&gt;
* Consult [[AppSuite:DB_user_privileges]] (or ''grep GRANT /opt/open-xchange/sbin/initconfigdb'') for an up-to-date list of required privileges. The following statement was correct as of the time of writing this section.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;br /&gt;
 mysql&amp;gt; GRANT CREATE, LOCK TABLES, REFERENCES, INDEX, DROP, DELETE, ALTER, SELECT, UPDATE, INSERT, CREATE TEMPORARY TABLES, SHOW VIEW, SHOW DATABASES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1'  WITH GRANT OPTION;&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXConfiguration&amp;diff=24010</id>
		<title>Template:OXConfiguration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXConfiguration&amp;diff=24010"/>
		<updated>2018-06-05T12:36:07Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Open-Xchange configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Open-Xchange configuration =&lt;br /&gt;
&lt;br /&gt;
To avoid confusion right at the start notice that Open-Xchange uses multiple administration levels and requires different credentials at some stages at the installation and server management. Note that the passwords chosen at this guide are weak and should be replaced by stronger passwords.&lt;br /&gt;
* The MySQL database user&lt;br /&gt;
** Username: openexchange&lt;br /&gt;
** Password used at this guide: db_password&lt;br /&gt;
** Responsibility: Execute all kinds of database operations&lt;br /&gt;
&lt;br /&gt;
* The Open-Xchange Admin Master&lt;br /&gt;
** Username: oxadminmaster&lt;br /&gt;
** Password used at this guide: admin_master_password&lt;br /&gt;
** Responsibility: Manage contexts, manage all kinds of low level server configuration&lt;br /&gt;
&lt;br /&gt;
* The Context Admin&lt;br /&gt;
** Username: oxadmin&lt;br /&gt;
** Password used at this guide: admin_password&lt;br /&gt;
** Responsibility: Manage users/groups/resources inside a context&lt;br /&gt;
&lt;br /&gt;
As stated above we assume the MySQL service has been installed previously, and it is running and available.&lt;br /&gt;
&lt;br /&gt;
A good idea is to add the Open-Xchange binaries to PATH:&lt;br /&gt;
&lt;br /&gt;
 $  echo PATH=$PATH:/opt/open-xchange/sbin/ &amp;gt;&amp;gt; ~/.bashrc &amp;amp;&amp;amp; . ~/.bashrc&lt;br /&gt;
&lt;br /&gt;
Now we have to initialize the Open-Xchange ''configdb'' database. This can all be done by executing the ''initconfigdb'' script.&lt;br /&gt;
&lt;br /&gt;
 $ /opt/open-xchange/sbin/initconfigdb --configdb-pass=db_password -a --mysql-root-passwd=root_password&lt;br /&gt;
&lt;br /&gt;
Use the ''--mysql-root-passwd'' option to supply the MySQL root password as configured during database installation.&lt;br /&gt;
&lt;br /&gt;
Add the ''-i'' option if you want to remove an already existing open-xchange configdb.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The -a parameter adds an ''openexchange'' account to MySQL. This account will be used for database connections from the OX App Suite middleware and requires ALL PRIVILEGES. You can also create that account manually [[OXLoadBalancingClustering_Database#Creating_Open-Xchange_user|during database installation / configuration]], in which case you can skip the ''-a'' parameter here.&lt;br /&gt;
&lt;br /&gt;
Before starting any service, all basic configuration files need to be set up correctly. The ''--configdb-pass'' option indicates the password of the ''openexchange'' database user previously created, the ''--master-pass'' options specifies the password of the Open-Xchange ''adminmaster'' user that will be created when executing the ''oxinstaller'' script.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:QuickInstIntro&amp;diff=24007</id>
		<title>Template:QuickInstIntro</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:QuickInstIntro&amp;diff=24007"/>
		<updated>2018-06-05T10:27:33Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#ifeq:{{{release|}}}|6|&lt;br /&gt;
This article will guide you through the installation of the Open-Xchange server, it describes the basic configuration and software requirements. As it is intended as a quick walk-through it assumes an existing installation of the operating system and requires average system administration skills. More, this guide will show you how to setup a basic installation with none of the typically used distributed environment settings. The objective of this guide is:&lt;br /&gt;
&lt;br /&gt;
* To setup a single server installation&lt;br /&gt;
* To setup a database for a single database service, no replication&lt;br /&gt;
* To setup a single Open-Xchange instance, no cluster&lt;br /&gt;
* To provide a basic configuration setup, no mailserver configuration&lt;br /&gt;
}}&lt;br /&gt;
{{#ifeq:{{{release|}}}|edp|&lt;br /&gt;
This article will guide you through the installation of the Open-Xchange server, it describes the basic configuration and software requirements. As it is intended as a quick walk-through it assumes an existing installation of the operating system and requires average system administration skills. More, this guide will show you how to setup a basic installation with none of the typically used distributed environment settings. The objective of this guide is:&lt;br /&gt;
&lt;br /&gt;
* To setup a single server installation&lt;br /&gt;
* To setup a database for a single database service, no replication&lt;br /&gt;
* To setup a single Open-Xchange instance, no cluster&lt;br /&gt;
* To provide a basic configuration setup, no mailserver configuration&lt;br /&gt;
}}&lt;br /&gt;
{{#ifeq:{{{release|}}}|appsuite|&lt;br /&gt;
This article will guide you through the installation of OX App Suite, it describes the basic configuration and software requirements. As it is intended as a quick walk-through it assumes an existing installation of the operating system and requires average system administration skills. More, this guide will show you how to setup a basic installation with none of the typically used distributed environment settings. The objective of this guide is:&lt;br /&gt;
&lt;br /&gt;
* To setup a single server installation&lt;br /&gt;
* To setup a database for a single database service, no replication&lt;br /&gt;
* To setup a single Open-Xchange instance, no cluster&lt;br /&gt;
* To provide a basic configuration setup, no mailserver configuration&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24006</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=24006"/>
		<updated>2018-06-05T10:23:01Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Standalone database setup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Note: the following list ist not an exclusive list or authorative statement about supported MySQL flavors / versions. Please consult the official support / system requirements statement.&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* MariaDB (10.1, 10.2): https://downloads.mariadb.org/&lt;br /&gt;
* Oracle MySQL Community Server (5.6, 5.7): https://dev.mysql.com/downloads/mysql/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 # oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service, and run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/pre&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Note: The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly. And use a real password.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT ALL PRIVILEGES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1';&lt;br /&gt;
 mysql&amp;gt; GRANT ALL PRIVILEGES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1';&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=23940</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=23940"/>
		<updated>2018-05-16T10:22:32Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
Note: the Oracle flavor is also valid, but not yet documented here.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB (5.6, 5.7): https://www.percona.com/downloads/&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://downloads.mariadb.org/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Start the service, and run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 service mysql start&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
Make sure the service is enabled by the OS's init system.&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/pre&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Note: The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly. And use a real password.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT ALL PRIVILEGES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1';&lt;br /&gt;
 mysql&amp;gt; GRANT ALL PRIVILEGES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1';&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=23939</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=23939"/>
		<updated>2018-05-16T10:21:02Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;). For POC or demo setups, a single standalone database setup might be sufficient.&lt;br /&gt;
&lt;br /&gt;
== Standalone database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database server, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
Note: the Oracle flavor is also valid, but not yet documented here.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB (5.6, 5.7): https://www.percona.com/downloads/&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://downloads.mariadb.org/&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
MySQL configuration advise is given in our [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information and create configuration files as described there.&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
You should now be able to restore your previously taken backup.&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with a standalone database ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases, and a standalone master works just as well, if we register it as a master, and not registering a slave.&lt;br /&gt;
&lt;br /&gt;
For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (which is set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct argument &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The single database is then used for reading and writing.&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/pre&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Note: The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly. And use a real password.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT ALL PRIVILEGES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1';&lt;br /&gt;
 mysql&amp;gt; GRANT ALL PRIVILEGES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1';&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Running_a_cluster&amp;diff=23907</id>
		<title>AppSuite:Running a cluster</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Running_a_cluster&amp;diff=23907"/>
		<updated>2018-04-24T09:06:31Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Rolling Upgrade without breaking Hazelcast upgrade */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Running a cluster&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Concepts =&lt;br /&gt;
&lt;br /&gt;
For inter-OX-communication over the network, multiple Open-Xchange servers can form a cluster. This brings different advantages regarding distribution and caching of volatile data, load balancing, scalability, fail-safety and robustness. Additionally, it provides the infrastructure for upcoming features of the Open-Xchange server. &lt;br /&gt;
The clustering capabilities of the Open-Xchange server are mainly built up on [http://hazelcast.com Hazelcast], an open source clustering and highly scalable data distribution platform for Java. The following article provides an overview about the current featureset and configuration options.&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
== Synchronized system clock times ==&lt;br /&gt;
It is crucial that all involved members in a cluster do have their system clock times in sync with each other; e.g. by using an NTP service.&lt;br /&gt;
&lt;br /&gt;
== HTTP routing ==&lt;br /&gt;
An OX cluster is always part of a larger picture. Usually there is front level loadbalancer as central HTTPS entry point to the platform. This loadbalancer optionally performs HTTPS termination and forwards HTTP(S) requests to webservers (the usual and only supported choice as of now is Apache). These webservers are performing HTTPS termination (if this is not happening on the loadbalancer) and serve static content, and (which is what is relevant for our discussion here) they forward dynamic requests to the OX backends.&lt;br /&gt;
&lt;br /&gt;
A central requirement for the interaction of these components (loadbalancer, webservers, OX nodes) is that we have session stability based on the JSESSIONID cookie / jsessionid path component suffix. This means that our application sets a cookie named JSESSIONID which has a value like &amp;lt;large decimal number&amp;gt;.&amp;lt;route identifier&amp;gt;, e.g. &amp;quot;5661584529655240315.OX1&amp;quot;. The route identifier here (&amp;quot;OX1&amp;quot; in this example) is taken by the OX node from a configuration setting from a config file and is specific to one OX node. HTTP routing must happen such that HTTP requests with a cookie with such a suffix always end up the corresponding OX node. There are furthermore specific cirumstances when passing this information via cookie is not possible. Then the JSESSIONID is transferred in a path component as &amp;quot;jsessionid=...&amp;quot; in the HTTP request. The routing mechanism needs to take that into account also.&lt;br /&gt;
&lt;br /&gt;
There are mainly two options to implement this. If the Apache processes are running co-located on the same machines running the OX groupware processes, it is often desired to have the front level loadbalancer perform HTTP routing to the correct machines. If dedicated Apache nodes are employed, is is usually sufficient to have the front-level loadbalancer do HTTP routing to the Apache nodes in a round-robin fashion and perform routing to the correct OX nodes in the Apache nodes.&lt;br /&gt;
&lt;br /&gt;
We provide sample configuration files to configure Apache (with mod_proxy_http) to perform HTTP routing correctly in our guides on OXpedia, e.g. [[AppSuite:Main_Page_AppSuite#quickinstall]]. Central elements are the directives &amp;quot;ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&amp;quot; in conjunction with the &amp;quot;route=OX1&amp;quot; parameters to the BalancerMember lines in the Proxy definition. This is valid for Apache 2.2 as of Sep-2014.&lt;br /&gt;
&lt;br /&gt;
How to configure a front level loadbalancer to perform HTTP equivalent HTTP routing is dependent on the specific loadbalancer implementation. If Apache is used as front level loadbalancer, the same configuration as discussed in the previous section can be employed. As of time of writing this text (Sep 2014), the alternative choices are thin. F5 BigIP is reported to be able to implement &amp;quot;jsessionid based persistence using iRules&amp;quot;. nginx has the functionality in their commercial &amp;quot;nginx plus&amp;quot; product. (Both of these options have not been tested by OX.) Other loadbalancers with this functionality are not known to us.&lt;br /&gt;
&lt;br /&gt;
If the front level loadbalancer is not capable of performing correct HTTP routing, is is required to configure correct HTTP routing on Apache level, even if Apache runs co-located on the OX nodes and thus cross-routing happens.&lt;br /&gt;
&lt;br /&gt;
There are several reasons why we require session stability in exactly this way. We require session stabilty for horizontal scale-out; while we support transparent resuming / migration of user sessions in the OX cluster without need for users to re-authenticate, sessions wandering around randomly will consume a fixed amount resources corresponding to a running session on each OX node in the cluster, while a session sticky to one OX node will consume this fixed amount of resources only on one OX node. Furthermore there are mechanisms in OX like TokenLogin which work only of all requests beloning to one sequence get routed to the same OX node even if they stem from different machines with different IPs. Only the JSESSIONID (which in this case is transferred as jsessionid path component, as cookies do not work during a 302 redirect, which is part of this sequence) carries the required information where the request must be routed to.&lt;br /&gt;
&lt;br /&gt;
Usual &amp;quot;routing based on cookie hash&amp;quot; is not sufficient here since it disregards the information which machine originally issued the cookie. It only ensures that the session will be sticky to any target, which statistically will not be the same machine that issued the cookie. OX will then set a new JSESSIONID cookie, assuming the session had been migrated. The loadbalancer will then route the session to a different target, as the hash of the cookie will differ. This procedure then happens iteratively until by chance the routing based on cookie hash will route the session to the correct target. By then, a lot of resources will have been wasted, by creating full (short-term) sessions on all OX nodes. Furthermore, processes like TokenLogin will not work this way.&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
&lt;br /&gt;
All settings regarding cluster setup are located in the configuration file ''hazelcast.properties''. The former used additional files ''cluster.properties'', ''mdns.properties'' and ''static-cluster-discovery.properties'' are no longer needed. The following gives an overview about the most important settings - please refer to the inline documentation of the configuration file for more advanced options.&lt;br /&gt;
&lt;br /&gt;
Note: The configuration guide targets v7.4.0 of the OX server (and above). For older versions, please consult the history of this page. A full list of Hazelcast-related properties is available at https://documentation.open-xchange.com/components/middleware/config/7.8.4/#mode=features&amp;amp;feature=Hazelcast .&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
To restrict access to the cluster and to separate the cluster from others in the local network, a name and password needs to be defined. Only backend nodes having the same values for those properties are able to join and form a cluster. &lt;br /&gt;
&lt;br /&gt;
 # Configures the name of the cluster. Only nodes using the same group name &lt;br /&gt;
 # will join each other and form the cluster. Required if &lt;br /&gt;
 # &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is not &amp;quot;empty&amp;quot; (see below).&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&lt;br /&gt;
 &lt;br /&gt;
 # The password used when joining the cluster. Defaults to &amp;quot;wtV6$VQk8#+3ds!a&amp;quot;. &lt;br /&gt;
 # Please change this value, and ensure it's equal on all nodes in the cluster.&lt;br /&gt;
 com.openexchange.hazelcast.group.password=wtV6$VQk8#+3ds!a&lt;br /&gt;
&lt;br /&gt;
== Network ==&lt;br /&gt;
&lt;br /&gt;
It's required to define the network interface that is used for cluster communication via ''com.openexchange.hazelcast.network.interfaces''. By default, the interface is restricted to the local loopback address only. To allow the same configuration amongst all nodes in the cluster, it's recommended to define the value using a wildcard matching the IP addresses of all nodes participating in the cluster, e.g. ''192.168.0.*''&lt;br /&gt;
&lt;br /&gt;
 # Comma-separated list of interface addresses hazelcast should use. Wildcards &lt;br /&gt;
 # (*) and ranges (-) can be used. Leave blank to listen on all interfaces&lt;br /&gt;
 # Especially in server environments with multiple network interfaces, it's &lt;br /&gt;
 # recommended to specify the IP-address of the network interface to bind to &lt;br /&gt;
 # explicitly. Defaults to &amp;quot;127.0.0.1&amp;quot; (local loopback only), needs to be &lt;br /&gt;
 # adjusted when building a cluster of multiple backend nodes.&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=127.0.0.1&lt;br /&gt;
&lt;br /&gt;
To form a cluster of multiple OX server nodes, different discovery mechanisms can be used. The discovery mechanism is specified via the property ''com.openexchange.hazelcast.network.join'':&lt;br /&gt;
&lt;br /&gt;
 # Specifies which mechanism is used to discover other backend nodes in the &lt;br /&gt;
 # cluster. Possible values are &amp;quot;empty&amp;quot; (no discovery for single-node setups),&lt;br /&gt;
 # &amp;quot;static&amp;quot; (fixed set of cluster member nodes) or &amp;quot;multicast&amp;quot; (automatic &lt;br /&gt;
 # discovery of other nodes via multicast). Defaults to &amp;quot;empty&amp;quot;. Depending on &lt;br /&gt;
 # the specified value, further configuration might be needed, see &amp;quot;Networking&amp;quot;&lt;br /&gt;
 # section below. &lt;br /&gt;
 com.openexchange.hazelcast.network.join=empty&lt;br /&gt;
&lt;br /&gt;
Generally, it's advised to use the same network join mechanism for all nodes in the cluster, and, in most cases, it's strongly recommended to use a ''static'' network join configuration. This will allow the nodes to join the cluster directly upon startup. With a ''multicast'' based setup, nodes will merge to an existing cluster possibly at some later time, thus not being able to access the distributed data until they've joined.&lt;br /&gt;
&lt;br /&gt;
Depending on the network join setting, further configuration may be necessary, as decribed in the following paragraphs.&lt;br /&gt;
&lt;br /&gt;
=== empty ===&lt;br /&gt;
&lt;br /&gt;
When using the default value ''empty'', no other nodes are discovered in the cluster. This value is suitable for single-node installations. Note that other nodes that are configured to use other network join mechanisms may be still able to still to connect to this node, e.g. using a ''static'' network join, having the IP address of this host in the list of potential cluster members (see below).&lt;br /&gt;
&lt;br /&gt;
=== static ===&lt;br /&gt;
&lt;br /&gt;
The most common setting for ''com.openexchange.hazelcast.network.join'' is ''static''. A static cluster discovery uses a fixed list of IP addresses of the nodes in the cluster. During startup and after a specific interval, the underlying Hazelcast library probes for not yet joined nodes from this list and adds them to the cluster automatically. The address list is configured via ''com.openexchange.hazelcast.network.join.static.nodes'':&lt;br /&gt;
&lt;br /&gt;
 # Configures a comma-separated list of IP addresses / hostnames of possible &lt;br /&gt;
 # nodes in the cluster, e.g. &amp;quot;10.20.30.12, 10.20.30.13:5701, 192.178.168.110&amp;quot;.&lt;br /&gt;
 # Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set to &amp;quot;static&amp;quot;. &lt;br /&gt;
 # It doesn't hurt if the address of the local host appears in the list, so &lt;br /&gt;
 # that it's still possible to use the same list throughout all nodes in the &lt;br /&gt;
 # cluster.&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=&lt;br /&gt;
&lt;br /&gt;
For a fixed set of backend nodes, it's recommended to simply include the IP addresses of all nodes in the list, and use the same configuration for each node. However, it's only required to add the address of at least one other node in the cluster to allow the node to join the cluster. Also, when adding a new node to the cluster and this list is extended accordingly, existing nodes don't need to be shut down to recognize the new node, as long as the new node's address list contains at least one of the already running nodes. &lt;br /&gt;
&lt;br /&gt;
=== multicast ===&lt;br /&gt;
&lt;br /&gt;
For highly dynamic setups where nodes are added and removed from the cluster quite often and/or the host's IP addresses are not fixed, it's also possible to configure the network join via multicast. During startup and after a specific interval, the backend nodes initiate the multicast join process automatically, and discovered nodes form or join the cluster afterwards. The multicast group and port can be configured as follows:&lt;br /&gt;
&lt;br /&gt;
 # Configures the multicast address used to discover other nodes in the cluster&lt;br /&gt;
 # dynamically. Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set &lt;br /&gt;
 # to &amp;quot;multicast&amp;quot;. If the nodes reside in different subnets, please ensure that &lt;br /&gt;
 # multicast is enabled between the subnets. Defaults to &amp;quot;224.2.2.3&amp;quot;. &lt;br /&gt;
 com.openexchange.hazelcast.network.join.multicast.group=224.2.2.3&lt;br /&gt;
 &lt;br /&gt;
 # Configures the multicast port used to discover other nodes in the cluster&lt;br /&gt;
 # dynamically. Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set &lt;br /&gt;
 # to &amp;quot;multicast&amp;quot;. Defaults to &amp;quot;54327&amp;quot;. &lt;br /&gt;
 com.openexchange.hazelcast.network.join.multicast.port=54327&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
&lt;br /&gt;
The following example shows how a simple cluster named ''MyCluster'' consisting of 4 backend nodes can be configured using ''static'' cluster discovery. The node's IP addresses are 10.0.0.15, 10.0.0.16, 10.0.0.17 and 10.0.0.18. Note that the same ''hazelcast.properties'' is used by all nodes.&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.group.name=MyCluster&lt;br /&gt;
 com.openexchange.hazelcast.group.password=secret&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=10.0.0.15,10.0.0.16,10.0.0.17,10.0.0.18&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=10.0.0.*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Advanced Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== Lite Members (available since v7.8.4) ===&lt;br /&gt;
&lt;br /&gt;
Lite members in a Hazelcast cluster are members that do not hold any data partitions, i.e. all read- and write operations to distributed maps are delegated to non-lite (&amp;quot;full&amp;quot;) members. Apart from not having data partitions, lite members participate in the same way as other members: they can register listeners for distributed topics (e.g. cache invalidation events) or can be addressed for task execution (e.g. during realtime communication). &lt;br /&gt;
&lt;br /&gt;
Similar to using a custom partitioning scheme, separating the nodes of a large cluster into few &amp;quot;full&amp;quot; members and many &amp;quot;lite&amp;quot; members helps to minimize the impact of JVM activities from a single node (mainly the garbage collector) on the whole cluster communication. Additionally, when starting or stopping lite members, no repartitioning of the distributed cluster data needs to be performed, which significantly decreases the node's startup- and shutdown time and reduces the necessary network communication to a minimum. &lt;br /&gt;
&lt;br /&gt;
In medium or larger sized clusters, it is sufficient to have roughly 10 to 20 percent of the nodes configured as &amp;quot;full&amp;quot; members, while all other ones can be started as &amp;quot;lite&amp;quot; member nodes. Additionally, please note that the configured backup count in the map configurations should always be smaller than the total number of &amp;quot;full&amp;quot; members, otherwise, there may be problems if one of those data nodes is shut down temporarily for maintenance. So, the minimum number of &amp;quot;full&amp;quot; members is implicitly bound to the sum of a map's ''backupCount'' and ''asyncBackupCount'' properties, plus ''1'' for the original data partition. &lt;br /&gt;
&lt;br /&gt;
The configured &amp;quot;full&amp;quot; members should preferrably not be used to serve client requests (by not adding them as endpoint in the loadbalancer), to ensure they are always responsive. Also, shutdown and startups of those &amp;quot;full&amp;quot; members should be reduced to a minimum to avoid repartitioning operations. &lt;br /&gt;
&lt;br /&gt;
More general information regarding lite members is available at http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#enabling-lite-members .&lt;br /&gt;
&lt;br /&gt;
To configure a node as &amp;quot;lite&amp;quot; member, the following configuration should be applied in the node's ''hazelcast.properties'' file:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.liteMember=true&lt;br /&gt;
&lt;br /&gt;
It's also recommended to use a &amp;quot;static&amp;quot; cluster discovery for the network join, and list all &amp;quot;full&amp;quot; member nodes here, so that join requests are handled by those nodes, too (and not the other nodes that are potentially prone to garbage collection delays. &lt;br /&gt;
&lt;br /&gt;
=== Custom Partitioning ===&lt;br /&gt;
&lt;br /&gt;
Note: Starting with v7.8.4, &amp;quot;Lite Members&amp;quot; should be used in favor of applying a custom partitioning scheme.&lt;br /&gt;
&lt;br /&gt;
While originally being designed to separate the nodes holding distributed data into different risk groups for increased fail safety, a custom partitioning strategy may also be used to distinguish between nodes holding distributed data from those who should not. &lt;br /&gt;
&lt;br /&gt;
This approach of custom partitioning may be used in a OX cluster, where usually different backend nodes serve different purposes. A common scenario is that there are nodes handling requests from the web interfaces, and others being responsible for USM/EAS traffic. Due to their nature of processing large chunks of synchronization data in memory, the USM/EAS nodes may encounter small delays when the Java garbage collector kicks in and suspends the Java Virtual Machine. Since those delays may also have an influence on hazelcast-based communication in the cluster, the idea is to instruct hazelcast to not store distributed data on that nodes. This is where a custom partitioning scheme comes into play.&lt;br /&gt;
&lt;br /&gt;
To setup a custom partitioning scheme in the cluster, an additional ''hazelcast.xml'' configuration file is used, which should be placed into the ''hazelcast'' subdirectory of the OX configuration folder, usually at ''/opt/openexchange/etc/hazelcast''. Please note that it's vital that each node in the cluster is configured equally here, so the same ''hazelcast.xml'' file should be copied to each server. The configuration read from there is used as basis for all further settings that are taken from the ordinary ''hazelcast.properties'' config file. &lt;br /&gt;
&lt;br /&gt;
To setup a custom partitioning scheme, the partition groups must be defined in the ''hazelcast.xml'' file. See the following file for an example configuration, where the three nodes ''10.10.10.60'', ''10.10.10.61'' and ''10.10.10.62'' are defined to form an own partitioning group each. Doing so, all distributed data will be stored at one of those nodes physically, while the corresponding backup data (if configured) at one of the other two nodes. All other nodes in the cluster will not be used to store distributed data, but will still be &amp;quot;full&amp;quot; hazelcast members, which is necessary for other cluster-wide operations the OX backends use. &lt;br /&gt;
&lt;br /&gt;
Please note that the configured backup count in the map configurations should be smaller than the number of nodes here, otherwise, there may be problems if one of those data nodes is shut down temporarily for maintenance. So, the minimum number of nodes to define in the partition group sections is implicitly bound to the sum of a map's ''backupCount'' and ''asyncBackupCount'' properties, plus ''1'' for the original data partition. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
 &amp;lt;!--&lt;br /&gt;
   ~ Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.&lt;br /&gt;
   ~&lt;br /&gt;
   ~ Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
   ~ you may not use this file except in compliance with the License.&lt;br /&gt;
   ~ You may obtain a copy of the License at&lt;br /&gt;
   ~&lt;br /&gt;
   ~ http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
   ~&lt;br /&gt;
   ~ Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
   ~ distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
   ~ See the License for the specific language governing permissions and&lt;br /&gt;
   ~ limitations under the License.&lt;br /&gt;
   --&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;hazelcast xsi:schemaLocation=&amp;quot;http://www.hazelcast.com/schema/config hazelcast-config-3.1.xsd&amp;quot;&lt;br /&gt;
            xmlns=&amp;quot;http://www.hazelcast.com/schema/config&amp;quot;&lt;br /&gt;
            xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;partition-group enabled=&amp;quot;true&amp;quot; group-type=&amp;quot;CUSTOM&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.60&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.61&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.62&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
     &amp;lt;/partition-group&amp;gt;&lt;br /&gt;
 &amp;lt;/hazelcast&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More general information regarding custom partioning is available at http://hazelcast.org/docs/latest/manual/html/partitiongroupconfig.html . &lt;br /&gt;
&lt;br /&gt;
It's also recommended to use a &amp;quot;static&amp;quot; cluster discovery for the network join, and list same the nodes that are also configured in the parition groups here, so that join requests are handled by those nodes, too (and not the other nodes that are potentially prone to garbage collection delays. &lt;br /&gt;
&lt;br /&gt;
After configuring a custom partitioning scheme, the data distribution may be verified, e.g. by inspecting the MBeans of the distributed maps via JMX.&lt;br /&gt;
&lt;br /&gt;
= Features =&lt;br /&gt;
&lt;br /&gt;
The following list gives an overview about different features that were implemented using the new cluster capabilities.&lt;br /&gt;
&lt;br /&gt;
== Distributed Session Storage ==&lt;br /&gt;
&lt;br /&gt;
Previously, when an Open-Xchange server was shutdown for maintenance, all user sessions that were bound to that machine were lost, i.e. the users needed to login again. With the distributed session storage, all sessions are backed by a distributed map in the cluster, so that they are no longer bound to a specific node in the cluster. When a node is shut down, the session data is still available in the cluster and can be accessed from the remaining nodes. The load-balancing techniques of the webserver then seamlessly routes the user session to another node, with no ''session expired'' errors. The distributed session storage comes with the package ''open-xchange-sessionstorage-hazelcast''. It's recommended to install this optional package in all clustered environments with multiple groupware server nodes.&lt;br /&gt;
&lt;br /&gt;
'''Notes:''' &lt;br /&gt;
* While there's some kind of built-in session distribution among the nodes in the cluster, this should not be seen as a replacement for session-stickiness between the loadbalancer and groupware nodes, i.e. one should still configure the webserver to use sticky sessions for performance reasons.&lt;br /&gt;
* The distributed session storage is still an in-memory storage. While the session data is distributed and backed up on multiple nodes in the cluster, shutting down multiple or all nodes at the same time will lead to loss of the the distributed data. To avoid such data loss when shutting down a node, please follow the guidelines at [[ Updating_a_Cluster ]].&lt;br /&gt;
&lt;br /&gt;
Depending on the cluster infrastructure, different backup-count configuration options might be set for the distributed session storage in the map configuration file ''sessions.properties'' in the ''hazelcast'' subdirectory:&lt;br /&gt;
&lt;br /&gt;
   com.openexchange.hazelcast.configuration.map.backupCount=1&lt;br /&gt;
&lt;br /&gt;
The ''backupcount'' property configures the number of nodes with synchronized backups. Synchronized backups block operations until backups are successfully copied and acknowledgements are received. If 1 is set as the backup-count for example, then all entries of the map will be copied to another JVM for fail-safety. 0 means no backup. Any integer between 0 and 6. Default is 1, setting bigger than 6 has no effect.&lt;br /&gt;
&lt;br /&gt;
   com.openexchange.hazelcast.configuration.map.asyncBackupCount=0&lt;br /&gt;
&lt;br /&gt;
The ''asyncbackup'' property configures the number of nodes with async backups. Async backups do not block operations and do not require acknowledgements. 0 means no backup. Any integer between 0 and 6. Default is 0, setting bigger than 6 has no effect.&lt;br /&gt;
&lt;br /&gt;
Since session data is backed up by default continuously by multiple nodes in the cluster, the steps described in [[ Session_Migration ]] to trigger session migration to other nodes explicitly is obsolete and no longer needed with the distributed session storage.&lt;br /&gt;
&lt;br /&gt;
Normally, sessions in the distributed storages are not evicted automatically, but are only removed when they're also removed from the session handler, either due to a logout operation or when exceeding the long-term session lifetime as configured by ''com.openexchange.sessiond.sessionLongLifeTime'' in ''sessiond.properties''. Under certain circumstances, i.e. the session is no longer accessed by the client and the OX node hosting the session in it's long-life container being shutdown, the remove operation from the distributed storage might not be triggered. Therefore, additionaly a maximum idle time of map-entries can be configured for the distributed sessions map via &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.configuration.map.maxIdleSeconds=640000&lt;br /&gt;
&lt;br /&gt;
To avoid unnecessary eviction, the value should be higher than the configured ''com.openexchange.sessiond.sessionLongLifeTime'' in ''sessiond.properties''.&lt;br /&gt;
&lt;br /&gt;
== Remote Cache Invalidation ==&lt;br /&gt;
&lt;br /&gt;
For faster access, groupware data is held in different caches by the server. Formerly, the caches utilized the TCP Lateral Auxiliary Cache plug in (LTCP) for the underlying JCS caches to broadcast updates and removals to caches on other OX nodes in the cluster. This could potentially lead to problems when remote invalidation was not working reliably due to network discovery problems. As an alternative, remote cache invalidation can also be performed using reliable publish/subscribe events built up on Hazelcast topics. This can be configured in the ''cache.properties'' configuration file, where the 'eventInvalidation' property can either be set to 'false' for the legacy behavior or 'true' for the new mechanism:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.caching.jcs.eventInvalidation=true&lt;br /&gt;
&lt;br /&gt;
All nodes participating in the cluster should be configured equally.&lt;br /&gt;
&lt;br /&gt;
Internally, if ''com.openexchange.caching.jcs.eventInvalidation'' is set to ''true'', LTCP is disabled in JCS caches. Instead, an internal mechanism based on distributed Hazelcast event topics is used to invalidate data throughout all nodes in the cluster after local update- and remove-operations. Put-operations aren't propagated (and haven't been with LTCP either), since all data put into caches can be locally loaded/evaluated at each node from the persistent storage layer.&lt;br /&gt;
&lt;br /&gt;
Using Hazelcast-based cache invalidation also makes further configuration of the JCS auxiliaries obsolete in the ''cache.ccf'' configuration file. In that case, all ''jcs.auxiliary.LTCP.*'' configuration settings are virtually ignored. However, it's still required to mark caches that require cluster-wide invalidation via ''jcs.region.&amp;lt;cache_name&amp;gt;=LTCP'', just as before. So basically, when using the new default setting ''com.openexchange.caching.jcs.eventInvalidation=true'', it's recommended to just use the stock ''cache.ccf'' file, since no further LTCP configuration is required.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
= Adminstration / Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
== Hazelcast Configuration ==&lt;br /&gt;
&lt;br /&gt;
The underlying Hazelcast library can be configured using the file ''hazelcast.properties''.&lt;br /&gt;
&lt;br /&gt;
'''Important''':&amp;lt;br&amp;gt;&lt;br /&gt;
By default property ''com.openexchange.hazelcast.network.interfaces'' is set to ''127.0.0.1''; meaning Hazelcast listens only to loop-back device. To build a cluster among remote nodes the appropriate network interface needs to be configured there. Leaving that property empty lets Hazelcast listen to all available network interfaces.&lt;br /&gt;
&lt;br /&gt;
The Hazelcast JMX MBean can be enabled or disabled with the property ''com.openexchange.hazelcast.jmx''. The properties ''com.openexchange.hazelcast.mergeFirstRunDelay'' and ''com.openexchange.hazelcast.mergeRunDelay'' control the run intervals of the so-called ''Split Brain Handler'' of Hazelcast that initiates the cluster join process when a new node is started. More details can be found at http://www.hazelcast.com/docs/2.5/manual/single_html/#NetworkPartitioning. &lt;br /&gt;
&lt;br /&gt;
The port ranges used by Hazelcast for incoming and outgoing connections can be controlled via the configuration parameters ''com.openexchange.hazelcast.networkConfig.port'', ''com.openexchange.hazelcast.networkConfig.portAutoIncrement'' and ''com.openexchange.hazelcast.networkConfig.outboundPortDefinitions''.&lt;br /&gt;
&lt;br /&gt;
== Commandline Tool ==&lt;br /&gt;
&lt;br /&gt;
To print out statistics about the cluster and the distributed data, the ''showruntimestats'' commandline tool can be executed witht the ''clusterstats'' ('c') argument. This provides an overview about the runtime cluster configuration of the node, other members in the cluster and distributed data structures.&lt;br /&gt;
&lt;br /&gt;
== JMX ==&lt;br /&gt;
&lt;br /&gt;
In the Open-Xchange server Java process, the MBean ''com.hazelcast'' can be used to monitor and manage different aspects of the underlying Hazelcast cluster. The ''com.hazelcast'' MBean provides detailed information about the cluster configuration and distributed data structures.&lt;br /&gt;
&lt;br /&gt;
== Hazelcast Errors ==&lt;br /&gt;
&lt;br /&gt;
When experiencing hazelcast related errors in the logfiles, most likely different versions of the packages are installed, leading to different message formats that can't be understood by nodes using another version. Examples for such errors are exceptions in hazelcast components regarding (de)serialization or other message processing.&lt;br /&gt;
This may happen when performing a consecutive update of all nodes in the cluster, where temporarily nodes with a heterogeneous setup try to communicate with each other. If the errors don't disappear after all nodes in the cluster have been update to the same package versions, it might be necessary to shutdown the cluster completely, so that all distributed data is cleared.&lt;br /&gt;
&lt;br /&gt;
== Cluster Discovery Errors ==&lt;br /&gt;
&lt;br /&gt;
* If the started OX nodes don't form a cluster, please double-check your configuration in ''hazelcast.properties''&lt;br /&gt;
* It's important to have the same cluster name defined in ''hazelcast.properties'' throughout all nodes in the cluster&lt;br /&gt;
* Especially when using multicast cluster discovery, it might take some time until the cluster is formed&lt;br /&gt;
* When using ''static'' cluster discovery, at least one other node in the cluster has to be configured in ''com.openexchange.hazelcast.network.join.static.nodes'' to allow joining, however, it's recommended to list all nodes in the cluster here&lt;br /&gt;
&lt;br /&gt;
== Disable Cluster Features ==&lt;br /&gt;
&lt;br /&gt;
The Hazelcast based clustering features can be disabled with the following property changes:&lt;br /&gt;
* Disable cluster discovery by setting ''com.openexchange.hazelcast.network.join'' to ''empty'' in ''hazelcast.properties''&lt;br /&gt;
* Disable Hazelcast by setting ''com.openexchange.hazelcast.enabled'' to false in ''hazelcast.properties''&lt;br /&gt;
* Disable message based cache event invalidation by setting ''com.openexchange.caching.jcs.eventInvalidation'' to ''false'' in ''cache.properties''&lt;br /&gt;
&lt;br /&gt;
== Update from 6.22.1 to version 6.22.2 and above ==&lt;br /&gt;
&lt;br /&gt;
As hazelcast will be used by default for the distribution of sessions starting 6.22.2 you have to adjust hazelcast according to our old cache configuration. First of all it's important that you install the open-xchange-sessionstorage-hazelcast package. This package will add the binding between hazelcast and the internal session management. Next you have to set a cluster name to the cluster.properties file (see [[#Cluster Discovery Errors]]). Furthermore you will have to add one of the two discovery modes mentioned in [[#Cluster Discovery]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Updating a Cluster =&lt;br /&gt;
&lt;br /&gt;
Running a cluster means built-in failover on the one hand, but might require some attention when it comes to the point of upgrading the services on all nodes in the cluster. This chapter gives an overview about general concepts and hints for silent updates of the cluster.&lt;br /&gt;
&lt;br /&gt;
== The Big Picture ==&lt;br /&gt;
&lt;br /&gt;
Updating an OX App Suite cluster is possible in several ways. The involved steps always include&lt;br /&gt;
&lt;br /&gt;
* Update the software by updating the packages through the distro's repository / software update tool&lt;br /&gt;
* Update the database schemas (so-called update tasks)&lt;br /&gt;
&lt;br /&gt;
There are some precautions required, though.&lt;br /&gt;
&lt;br /&gt;
=== Update Tasks Management ===&lt;br /&gt;
&lt;br /&gt;
It is a feature of the OX App Suite middleware to automatically start update tasks on a database schema when a user tries to login whose context lives on that schema. For installations beyond a certain size, if you just update the OX App Suite software without special handling of the update tasks, user logins will trigger an uncontrolled storm of update tasks on the databases, potentially leading to resource contention, unnecessary long update tasks runtimes, excessive load on the database server, maybe even service outages.&lt;br /&gt;
&lt;br /&gt;
So one key element of every update strategy is to avoid user logins on nodes which have already been updated to the new software version, while the database schemas are still on the old version. There are two fundamentally different approaches to this goal: use either a full downtime, or use a rolling update strategy.&lt;br /&gt;
&lt;br /&gt;
We describe the update strategy in more detail in the next section. Note that these are still high-level outlines of the actual procedure, which requires additional details with regards to Hazelcast, given further down below.&lt;br /&gt;
&lt;br /&gt;
==== Full downtime approach ====&lt;br /&gt;
&lt;br /&gt;
The full downtime approach is quite straightforward and involves&lt;br /&gt;
&lt;br /&gt;
* shutdown of all OX middleware nodes&lt;br /&gt;
* update the software on all OX App Suite (middleware and frontend) nodes&lt;br /&gt;
* execute the update tasks in a controlled way from one OX node&lt;br /&gt;
* restore the service&lt;br /&gt;
&lt;br /&gt;
This is the most general approach and always available, even if the rolling approach is not available due to Hazelcast constraints.&lt;br /&gt;
&lt;br /&gt;
==== Rolling strategy ====&lt;br /&gt;
&lt;br /&gt;
It is possible to execute the update tasks decoupled from the real update of the rest from the cluster, days or even weeks ahead of time, with the following approach:&lt;br /&gt;
&lt;br /&gt;
* If the load situation allows for it, take one node out of the loadbalancer (we call it the upgrade node). Otherwise, add a dedicated upgrade node to your cluster, identically configured to the other middleware nodes.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node&lt;br /&gt;
* update the software on the upgrade node&lt;br /&gt;
* execute all update tasks from the update node.&lt;br /&gt;
&lt;br /&gt;
In the last step, users from affected schemas will be logged out and denied service while the update tasks are running on their database schema. This is typically a short unavailability (some minutes) for a small part (1000...7000 depending on the installation) of the user base. This unavailability is of much lower impact than the unavailability of a full downtime, but you still might want to do this in the off-business hours.&lt;br /&gt;
&lt;br /&gt;
This way you end up with the production cluster running on the old version of OX App Suite, with the database already being upgraded to the next version. This is explicitly a valid and supported configuration. This approach offers the advantage that update tasks can be executed in advance, instead of doing them while the whole system is in a full maintenance downtime. Since update tasks can take some time, this is a considerable advantage.&lt;br /&gt;
&lt;br /&gt;
For the actual upgrade of the production cluster, the remaining steps are:&lt;br /&gt;
&lt;br /&gt;
* Upgrade and restart the OX App Suite software on one middleware node after another, one by one&lt;br /&gt;
* Upgrade the software on the OX App Suite frontend nodes (if these are separate nodes from the middleware nodes)&lt;br /&gt;
&lt;br /&gt;
Hazelcast will ensure that sessions from nodes which you restart are taken over by other nodes in the cluster, so ideally this step works without losing user sessions.&lt;br /&gt;
&lt;br /&gt;
For the rolling strategy to work as described, it is required that the old and new version of OX App Suite use compatible versions of the Hazelcast library. This is the case for most upgrades. However some upgrades must handle the situation that the new version of OX App Suite ships with a new version of Hazelcast incompatible to the version of Hazelcast shipped with the old version of OX App Suite. It will be stated in the release notes if this is the case for a given release. If so, then some additional steps are required during a rolling update to ensure session handling / invalidating during update tasks works properly. See below.&lt;br /&gt;
&lt;br /&gt;
== HOWTO / step-by-step instructions ==&lt;br /&gt;
&lt;br /&gt;
* Take backups of as much as possible (databases, OX config files, etc).&lt;br /&gt;
* Announce the maintenance to the users. The communication depends on which approach you chose: the full downtime approach will come with a full downtime for all users, while the rolling upgrade approach will result in some users will have a short loss of service while their schema upgrades.&lt;br /&gt;
&lt;br /&gt;
=== Full downtime approach ===&lt;br /&gt;
&lt;br /&gt;
* Initiate maintenance: Block HTTP sessions to the service. Put a reasonable maintenance page in place, probably some HTTP error 503 with a reasonable Retry-After header.&lt;br /&gt;
* Shutdown the service on all middleware nodes. Upgrade the software on all middleware and frontend nodes using the disto's package manager. See [[AppSuite:UpdatingOXPackages]] for details on how to do that. Don't forget the &amp;lt;code&amp;gt;touch-appsuite&amp;lt;/code&amp;gt; step if required (&amp;quot;If you update only UI plugins without simultaneously upgrading the core UI packages to a new version&amp;quot;).&lt;br /&gt;
* Start the &amp;lt;code&amp;gt;open-xchange&amp;lt;/code&amp;gt; service on one node&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that, in particular the [[UpdateTasks#How_to_see_all_schemas.3F|section]] about limited parallel execution.&lt;br /&gt;
* Start the &amp;lt;code&amp;gt;open-xchange&amp;lt;/code&amp;gt; services on the middleware nodes.&lt;br /&gt;
* Perform some crosschecks like&lt;br /&gt;
** all middleware nodes joined the Hazelcast cluster&lt;br /&gt;
** all OSGI bundles (which are expected to be running) are running&lt;br /&gt;
** WebUI login is possible&lt;br /&gt;
** Some central functionality tests like sending mails, accessing drive, etc&lt;br /&gt;
* Restore service: allow HTTP sessions, remove the maintenance page.&lt;br /&gt;
&lt;br /&gt;
=== Rolling Upgrade without breaking Hazelcast upgrade ===&lt;br /&gt;
&lt;br /&gt;
Remember: as stated above, this is viable only if the release notes for the new version do not state that there are breaking Hazelcast changes. For example, with v7.8.4 there were breaking Hazelcast changes and in the Release Notes it was stated as follows.&lt;br /&gt;
&lt;br /&gt;
https://software.open-xchange.com/products/appsuite/doc/Release_Notes_for_Release_7.8.4_2017-05-23.pdf&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Important - Please Note&lt;br /&gt;
&lt;br /&gt;
There is a major Hazelcast library update to OX App Suite v7.8.4. This means that when updating from an earlier backend version, due to the upgraded library, it is not possible to form a cluster of nodes that run previous version of Hazelcast (i.e. exiting volatile data in the cluster will be lost during the update). A consistent Hazelcast cluster is needed for cluster-wide cache invalidation. To circumvent problems with database update tasks that need to perform cache invalidation, please follow the steps described here: http://oxpedia.org/wiki/index.php?title=AppSuite:Running_a_cluster#Upgrades_of_the_Hazelcast_library. Please also note that session migration is not possible between versions. This usually affects all user sessions that are stored in a distributed map, and will require the users to re-login after the update. Running incompatible versions of Hazelcast within a cluster will result in logentries showing the conflicting node and version information.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you find you are upgrading to a version with breaking Hazelcast changes, please consult the next section [[#Rolling_Upgrade_with_breaking_Hazelcast_upgrade]].&lt;br /&gt;
&lt;br /&gt;
==== Description of the upgrade process ====&lt;br /&gt;
&lt;br /&gt;
The procedure consists of a '''pre-update''' where one update node will be taken out of the HTTP traffic, to execute database update tasks from that node, and a '''real update''', where all of the cluster nodes will get updated to the new version of the software.&lt;br /&gt;
&lt;br /&gt;
The pre-update will not make the new version of the software available to the users. It will run as kind of &amp;quot;background task&amp;quot;, mostly invisible for the users (but see below for a description of the impact of the update tasks on user experience).&lt;br /&gt;
&lt;br /&gt;
==== Pre-update ====&lt;br /&gt;
&lt;br /&gt;
The following steps all refer to one special middleware node, the so-called ''upgrade node''. The other cluster nodes are not affected by this step.&lt;br /&gt;
&lt;br /&gt;
* Take one middleware node (the upgrade node) out of the HTTP traffic by adjusting the apache mod_proxy tables. We propose a combination of the balancer_manager to do this during runtime without restart, but also update the config files to prevent service restarts of apache to accidentally route sessions to the upgrade node.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node &lt;br /&gt;
* Update packages on the upgrade node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that.&lt;br /&gt;
** Note that executing update tasks on database schemas will result in users from the given database schema to be logged out and locked out during the update tasks.&lt;br /&gt;
** You might want to keep the load low on the DBs, to affect production operations as low as possible, and because with this decoupled update tasks approach there is no immediate time pressure. If you want to follow the [[UpdateTasks#How_to_see_all_schemas.3F|limited parallel]] approach, use a small, mild parallelity factor (e.g. 2 or maybe 4 if you know this by far does not saturate your DB platform).&lt;br /&gt;
&lt;br /&gt;
==== Real Update ====&lt;br /&gt;
&lt;br /&gt;
The following steps refer to all cluster nodes (but the upgrade node, which had been updated before).&lt;br /&gt;
&lt;br /&gt;
* For one middleware cluster node after each nother:&lt;br /&gt;
** Update packages on that middleware node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
** Verify the node starts its bundles, joins the Hazelcast cluster, log files are clean, the node handles sessions&lt;br /&gt;
* For one frontend node after each other (if you've got separate frontend nodes):&lt;br /&gt;
** Update packages on that frontend node. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Finally, if required (&amp;quot;If you update only UI plugins without simultaneously upgrading the core UI packages to a new version&amp;quot;), execute &amp;lt;code&amp;gt;touch-appsuite&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;--timestamp&amp;lt;/code&amp;gt; argument as described on the page [[AppSuite:UpdatingOXPackages]]&lt;br /&gt;
* Perform final crosschecks like&lt;br /&gt;
** all middleware nodes joined the Hazelcast cluster&lt;br /&gt;
** all OSGI bundles (which are expected to be running) are running&lt;br /&gt;
** WebUI login is possible&lt;br /&gt;
** Some central functionality tests like sending mails, accessing drive, etc&lt;br /&gt;
&lt;br /&gt;
=== Rolling Upgrade with breaking Hazelcast upgrade ===&lt;br /&gt;
&lt;br /&gt;
Cf [[#Upgrades_of_the_Hazelcast_library]] below.&lt;br /&gt;
&lt;br /&gt;
In principle the steps given in the previous section apply. However the upgrade needs to get the special Hazelcast Upgrade Package installed (e.g. one from &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-76x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-780-782&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-783&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-784&amp;lt;/code&amp;gt;, ...) during execution of the update tasks.&lt;br /&gt;
&lt;br /&gt;
So the pre-update steps look like:&lt;br /&gt;
&lt;br /&gt;
* Take one middleware node (the upgrade node) out of the HTTP traffic by adjusting the apache mod_proxy tables. We propose a combination of the balancer_manager to do this during runtime without restart, but also update the config files to prevent service restarts of apache to accidentally route sessions to the upgrade node.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node &lt;br /&gt;
* Update packages on the upgrade node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Install the special Hazelcast Upgrade Package on the upgrade node (e.g. one from &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-76x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-780-782&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-783&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-784&amp;lt;/code&amp;gt;, ...). Restart the service again.&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that. You might want to keep the load low on the DBs, to affect production operations as low as possible, and because with this decoupled update tasks approach there is no immediate time pressure. If you want to follow the [[UpdateTasks#How_to_see_all_schemas.3F|limited parallel]] approach, use a small, mild parallelity factor (e.g. 2 or maybe 4 if you know this by far does not saturate your DB platform).&lt;br /&gt;
&lt;br /&gt;
Note: don't worry if you don't see the upgrade node joining the legacy cluster: the upgrade node will not join the legacy cluster / not be visisble there since the upgrade node will be a so-called &amp;quot;native client&amp;quot; to the legacy cluster, and it will be created on the fly (and subsequently disposed again) for propagating an event. So also on &amp;lt;code&amp;gt;netstat&amp;lt;/code&amp;gt; level the upgrade node will not have visible connections to the legacy cluster (unless for the very short timeframe when an actual even is sent). You can verify the functionality of that package by log lines like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; Successfully initialzed Hazelcast client: &amp;lt;client-id&amp;gt;&lt;br /&gt;
 Successfully got reference to cache event topic: cacheEvents-3&lt;br /&gt;
 Publishing legacy cache event: &amp;lt;cache-event&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Successfully published legacy cache event, shutting down client after 546ms...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the overly prudent it might be an idea to prepare a special test context with a test user living in its dedicated (test) schema, so you can test the functionality of this mechanis during upgrade first.&lt;br /&gt;
&lt;br /&gt;
After the DB update tasks you can remove the special upgrade package again from the upgrade node.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Real Upgrade&amp;quot; procedure then looks like [[#Rolling_Upgrade_without_breaking_Hazelcast_upgrade|above]].&lt;br /&gt;
&lt;br /&gt;
== Reference Documentation ==&lt;br /&gt;
&lt;br /&gt;
=== Limitations ===&lt;br /&gt;
&lt;br /&gt;
While in most cases a seamless, rolling upgrade of all nodes in the cluster is possible, there may be situations where nodes running a newer version of the Open-Xchange Server are not able to communicate with older nodes in the cluster, i.e. can't access distributed data or consume incompatible event notifications - especially, when the underlying Hazelcast library is part of the update, which does not support this scenario at the moment. In such cases, the release notes will contain corresponding information, so please have a look there before applying an update.&lt;br /&gt;
&lt;br /&gt;
Additionally, there may always be some kind of race conditions during an update, i.e. client requests that can't be completed successfully or internal events not being deliverd to all nodes in the cluster. That's why the following information should only serve as a best-practices guide to minimize the impact of upgrades to the user experience.&lt;br /&gt;
&lt;br /&gt;
=== Upgrading a single Node ===&lt;br /&gt;
&lt;br /&gt;
Upgrading all nodes in the cluster should usually be done sequentially, i.o.w. one node after the other. This means that during the upgrade of one node, the node is temporarily disconnected from the other nodes in the cluster, and will join the cluster again after the update is completed. From the backend perspective, this is as easy as stopping the open-xchange service. other nodes in the cluster will recognize the disconnected node and start to repartition the shared cluster data automatically. But wait a minute - doing so would potentially lead to the webserver not registering the node being stopped immediately, resulting in temporary errors for currently logged in users until they are routed to another machine in the cluster. That's why it's good practice to tell the webserver's load balancer that the node should no longer fulfill incoming requests. The Apache Balancer Manager is an excellent tool for this ([http://httpd.apache.org/docs/2.2/mod/mod_status.html module ''mod_status'']). Look at the screen shot. Every node can be put into a disabled mode. Further requests will the redirected to other nodes in the cluster:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:balancer_manager.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Afterwards, the open-xchange service on the disabled node can be stopped by executing:&lt;br /&gt;
&lt;br /&gt;
 $ /etc/init.d/open-xchange stop&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 $ service open-xchange stop&lt;br /&gt;
&lt;br /&gt;
Now, the node is effectively in maintenance mode and any updates can take place. One could now verify the changed cluster infrastructure by accessing the Hazelcast MBeans either via JMX or the ''showruntimestats -c'' commandline tool (see above for details). There, the shut down node should no longer appear in the 'Member' section (com.hazelcast:type=Member).&lt;br /&gt;
&lt;br /&gt;
When all upgrades are processed, the node open-xchange service can be started again by executing:&lt;br /&gt;
&lt;br /&gt;
 $ /etc/init.d/open-xchange start&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 $ service open-xchange start&lt;br /&gt;
&lt;br /&gt;
As stated above, depending on the chosen cluster discovery mechanism, it might take some time until the node joins the cluster again. When using static cluster discovery, it will join the existing cluster usually directly during serivce startup, i.o.w. before other depending OSGi services are started. Otherwise, there might also be situations where the node cannot join the cluster directly, for example when there were no mDNS advertisments for other nodes in the cluster received yet. Then, it can take some additional time until the node finally joins the cluster. During startup of the node, you can observe the JMX console or the output of ''showruntimestats -c'' (com.hazelcast:type=Member) of another node in the cluster to verify when the node has joined. &lt;br /&gt;
&lt;br /&gt;
After the node has joined, distributed data is re-partioned automatically, and the node is ready to server incoming requests again - so now the node can finally be enabled again in the load balancer configuration of the webserver. Afterwards, the next node in the cluster can be upgraded using the same procedure, until all nodes were processed.&lt;br /&gt;
&lt;br /&gt;
=== Upgrades of the Hazelcast library ===&lt;br /&gt;
&lt;br /&gt;
In case an upgrade includes a major update of the Hazelcast library, a newly upgraded node will usually not be able to connect to the nodes running the previous version. In this case, volatile cluster data is lost after all nodes in the cluster have been updated, including sessions held in the distributed session storage. As outlined above, the release notes will contain a corresponding warning in such cases.&lt;br /&gt;
&lt;br /&gt;
Besides upgraded nodes not being able to access distributed data of the legacy cluster, this also affects new data not being available in the legacy cluster, which may cause troubles if the updated backend version needs to perform database update tasks. Database update tasks usually operate in a &amp;quot;blocking&amp;quot; way and all contexts associated with the schema being upgraded are disabled temporarily. Since context data itself is being held in caches on potentially each node in the cluster, the affected cache entries are invalidated during the database update. And, since cluster-wide cache invalidations again utilize Hazelcast functionality ([[#Remote Cache Invalidation]]), such invalidations normally won't be propagated to nodes running a previous version of the Hazelcast library.&lt;br /&gt;
&lt;br /&gt;
To work around this specific scenario where an incompatible upgrade of the Hazelcast library needs to be performed along with blocking database update tasks, starting with v7.8.0, a supplementary package is available that explicitly enables the context cache invalidation of nodes running the previous Hazelcast library. This package follows the naming scheme ''open-xchange-cluster-upgrade-from-XXX'' (where XXX representing the version of the legacy version of the Open-Xchange server), and is available in the repositories for the updated server packages. This package should only be installed on the first node of the cluster that is going to be upgraded to the new version, and can be deactivated once the database upgrade tasks were executed successfully. &lt;br /&gt;
&lt;br /&gt;
Once installed, a legacy cluster is discovered based on the available information in the ''hazelcast.properties'' configuration file in case cluster discovery is set to ''static''. If ''multicast'' is used, there's an alternative option to configure at least one of the addresses of the legacy cluster via ''com.openexchange.hazelcast.network.client.nodes''.&lt;br /&gt;
&lt;br /&gt;
As an example, along with the server v7.8.0, a new package named ''open-xchange-cluster-upgrade-from-76x'' can be installed that aids in invalidating cluster server nodes running v7.6.x (which includes the Hazelcast library in version 3.2.4). Using this package, the recommended steps to update an OX cluster from version 7.6.x to version 7.8.0 would be:&lt;br /&gt;
# Pick a node from your cluster that you want to use for executing the database update tasks shipped with the new release&lt;br /&gt;
# Disable this node for incoming HTTP requests in your webserver configuration as described at [[#Upgrading a single Node]]&lt;br /&gt;
# Update the OX packages on this node, additionally install the package ''open-xchange-cluster-upgrade-from-76x''&lt;br /&gt;
# Restart the open-xchange services on this node&lt;br /&gt;
# Trigger the update task executions using the ''runUpdate'' commandline utitlty as described at [[UpdateTasks]]&lt;br /&gt;
# Once they are finished, uninstall the package ''open-xchange-cluster-upgrade-from-76x'' again&lt;br /&gt;
# Restart the open-xchange services on this node&lt;br /&gt;
# Re-enable the node for incoming HTTP requests in your webserver configuration as described at [[#Upgrading a single Node]]&lt;br /&gt;
# Upgrade all other nodes in the cluster as described at [[#Upgrading a single Node]]&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.0 through v7.8.2 (incl.) to v7.8.3 using the package named ''open-xchange-cluster-upgrade-from-780-782'', since v7.8.0 through v7.8.2 (incl.) utilize Hazelcast v3.5.x, while v7.8.3 uses Hazelcast v3.6.4&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.3 to v7.8.4 using the package named ''open-xchange-cluster-upgrade-from-783'', since v7.8.3 utilizes Hazelcast v3.7.1&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.4 to v7.10.0 using the package named ''open-xchange-cluster-upgrade-from-784'', since v7.8.4 utilizes Hazelcast v3.8.1&lt;br /&gt;
&lt;br /&gt;
'''Operations Note:''' The upgraded node will be added as so-called [http://docs.hazelcast.org/docs/2.3/manual/html/ch15.html Native Client] to the legacy Hazelcast Cluster.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Native Client enables you to do all Hazelcast operations without being a member of the cluster.&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
However Native client is not member and relies on one of the cluster members.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means, the upgraded node will not be visible in the members list of the legacy Hazelcast cluster (&amp;lt;code&amp;gt;showruntimestats -c&amp;lt;/code&amp;gt;). Furthermore, the native client will created and destructed on single context events, with the effect that connections will only be visible in the very moment of such an event. This means effectively that verification of the invalidation mechanis is only possible by actually executing the &amp;lt;code&amp;gt;runupdate&amp;lt;/code&amp;gt; CLT. This should produce log lines like&lt;br /&gt;
&lt;br /&gt;
 Successfully initialzed Hazelcast client: &amp;lt;client-id&amp;gt;&lt;br /&gt;
 Successfully got reference to cache event topic: cacheEvents-3&lt;br /&gt;
 Publishing legacy cache event: &amp;lt;cache-event&amp;gt;&lt;br /&gt;
 Successfully published legacy cache event, shutting down client after 546ms...&lt;br /&gt;
&lt;br /&gt;
Most importantly, you should be able to observe correct functionality (users of affected contexts being logged out). It may be handy to prepare a dedicated schema with just test contexts inside. (How to create this is out of scope here, but hint: use &amp;lt;code&amp;gt;createschema&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;createcontext --schema-name&amp;lt;/code&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
=== Other Considerations ===&lt;br /&gt;
&lt;br /&gt;
* It's always recommended to only upgrade one node after the other, always ensuring that the cluster has formed correctly between each shutdown/startup of a node.&lt;br /&gt;
* Do not stop a node while running the runUpdate script or the associated update task.&lt;br /&gt;
* During the time of such a rolling upgrade of all nodes, we have effectively heterogeneous software versions in the cluster, which potentially might lead to temporary inconsistencies. Therefore, all nodes in the cluster should be updated in one cycle (but still one after the other).&lt;br /&gt;
* Following the above guideline, it's also possible to add or remove nodes dynamically to the cluster, not only when disconnecting a node temporary for updates.&lt;br /&gt;
* In case of trouble, i.e. a node refuses to join the cluster again after restart, consult the logfiles first for any hints about what is causing the problem - both on the disconnected node, and also on other nodes in the network&lt;br /&gt;
* If there are general incompatibilities between two revisions of the Open-Xchange Server that prevent an operation in a cluster (release notes), it's recommended to choose another name for the cluster in ''cluster.properties'' for the nodes with the new version. This will temporary lead to two separate clusters during the rolling upgrade, and finally the old cluster being shut down completely after the last node was updated to the new version. While distributed data can't be migrated from one server version to another in this scenario due to incompatibilities, the uptime of the system itself is not affected, since the nodes in the new cluster are able to serve new incoming requests directly.&lt;br /&gt;
* When updating only UI plugins without also updating to a new version of the core UI, you also need to perform the additional step from [[AppSuite:UpdatingOXPackages#Updating_UI_plugins|Updating UI plugins]].&lt;br /&gt;
&lt;br /&gt;
[[Category: AppSuite]] [[Category: Administration]] [[Category: Cluster]]&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23840</id>
		<title>User:Dominik.epple/DocumentConverterInstall</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23840"/>
		<updated>2018-02-16T15:01:54Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Final setup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrough.&lt;br /&gt;
&lt;br /&gt;
The other relevant documentation is to be considered as a reference.&lt;br /&gt;
&lt;br /&gt;
This document describes the fully clustered setup. Simpler setups can be deduced as special case.&lt;br /&gt;
&lt;br /&gt;
This document has been created and verified on CentOS7 and Debian Jessie, using OX App Suite 7.8.4.&lt;br /&gt;
&lt;br /&gt;
= Design description =&lt;br /&gt;
&lt;br /&gt;
We consider a clustered setup with multiple middleware nodes and multiple converter nodes.&lt;br /&gt;
&lt;br /&gt;
We consider a high available connection from the middleware nodes to the converter nodes realized using HAproxy instances running locally on the middleware nodes which do simple round-robin to the Apache instances of the Fronted nodes, which will do ''correct'' session stickyness aware routing to the converter nodes.&lt;br /&gt;
&lt;br /&gt;
We need the Apache instances to get correct ''session sticky'' routing behavior.&lt;br /&gt;
&lt;br /&gt;
We need the HAproxy instances to connect to the Apache instances in a high available fashion. If there are other means in the infrastructure offering that functionality, this is also okay. We present the HAproxy based setup to give an example of a fully working setup.&lt;br /&gt;
&lt;br /&gt;
= Software installation and configuration =&lt;br /&gt;
&lt;br /&gt;
Note: this guide is written distro-agnostic, so please use the distro's appropriate command for installing packages.&lt;br /&gt;
&lt;br /&gt;
Repos to be used are the standard repo definitions from https://software.open-xchange.com/products/.&lt;br /&gt;
&lt;br /&gt;
== Middleware nodes ==&lt;br /&gt;
&lt;br /&gt;
Prerequisites: Drive is installed and working. We need Drive to upload test documents and verify their conversion. This also assumes (since we are discussing a clustered setup) a clustered filestore is available and working. If you are only going for a single node proof-of-concept setup, that is not relevant of course.&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-api open-xchange-documentconverter-client&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/opt/open-xchange/etc/permissions.properties:&lt;br /&gt;
# assume a global switch on for testing. further config cascade stuff etc is out of scope&lt;br /&gt;
# of this document.&lt;br /&gt;
com.openexchange.capability.document_preview=true&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://host[:port]/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frontend nodes ==&lt;br /&gt;
&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
== Converter nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-server open-xchange-documentconverter-api readerengine&lt;br /&gt;
&lt;br /&gt;
(Note: the official documentation also mentions &amp;quot;pdf2svg&amp;quot; which at least on CentOS7 does not exist, but rather a package named &amp;quot;readerengine-pdf2svg&amp;quot; is pulled as dependency. So for the moment let's assume we don't need to install that explicitly, but if you are following this guide on Debian you should double-check.)&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/etc/server.properties:&lt;br /&gt;
 # Pick a unique route, which will be configured consistently in apache&lt;br /&gt;
 com.openexchange.server.backendRoute=DC1&lt;br /&gt;
 # Clustered setups need to listen not only on localhost&lt;br /&gt;
 com.openexchange.connector.networkListenerHost=*&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/documentconverter/etc/documentconverter.properties &lt;br /&gt;
 # TODO figure out the recommended Cache setup for a clustered scenario&lt;br /&gt;
 com.openexchange.documentconverter.RemoteCacheUrls = ?&lt;br /&gt;
 # Default is 3. Adjust for your sizing.&lt;br /&gt;
 com.openexchange.documentconverter.jobProcessorCount=3&lt;br /&gt;
&lt;br /&gt;
Services configuration:&lt;br /&gt;
&lt;br /&gt;
 systemctl start open-xchange-documentconverter-server&lt;br /&gt;
 systemctl enable open-xchange-documentconverter-server&lt;br /&gt;
&lt;br /&gt;
Note: you don't need ConfigDB / any DB access. Don't connect the converter nodes to any database. Don't make it join any Hazelcast cluster. No further configuration is required.&lt;br /&gt;
&lt;br /&gt;
If you are annoyed by the &amp;quot;unable to connect to ConfigDB&amp;quot; (false) error messages in the logs, you can configure logback to suppress them (TODO: add information how to do that).&lt;br /&gt;
&lt;br /&gt;
= Configure the middleware to converter connectivity =&lt;br /&gt;
&lt;br /&gt;
So that was the trivial part. Now it gets interesting.&lt;br /&gt;
&lt;br /&gt;
== First test: direct connectivity ==&lt;br /&gt;
&lt;br /&gt;
Pick a middleware node. Configure direct connection to one converter service which is called &amp;lt;code&amp;gt;dc1&amp;lt;/code&amp;gt;. By default the service listens on port &amp;lt;code&amp;gt;8008&amp;lt;/code&amp;gt; and listens on the path &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://dc1:8008/documentconverterws/&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In particular, you should see&lt;br /&gt;
&lt;br /&gt;
* HTTP status code 200 (not shown for clarity, but you can verify with &amp;lt;code&amp;gt;curl -v&amp;lt;/code&amp;gt;)&lt;br /&gt;
* &amp;lt;code&amp;gt;WebService is running...&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Error Code: 0&amp;quot;.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If that is successful, go ahead and configure that URL in the middleware node&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://dc1:8008/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do a testing cycle as described below.&lt;br /&gt;
&lt;br /&gt;
If everything works, you confirmed that the middleware node and the converter node are configured correctly.&lt;br /&gt;
&lt;br /&gt;
Now ensure all your middleware nodes and all your converter nodes are configured likewise. Make sure the converter nodes get unique &amp;lt;code&amp;gt;com.openexchange.server.backendRoute&amp;lt;/code&amp;gt; values (see above).&lt;br /&gt;
&lt;br /&gt;
== Second test: use Apache for loadbalancing ==&lt;br /&gt;
&lt;br /&gt;
Pick one frontend node to configure its Apache for loadbalancing for the converter nodes.&lt;br /&gt;
&lt;br /&gt;
There are sample configuration stanzas in our default configuration. They are just fine. Just make sure the &amp;lt;code&amp;gt;route&amp;lt;/code&amp;gt; parameters match the ones from the converter nodes.&lt;br /&gt;
&lt;br /&gt;
I want to emphasize to configure the &amp;lt;code&amp;gt;Allow&amp;lt;/code&amp;gt; line correctly. The &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt; endpoint must not be made available publicly!&lt;br /&gt;
&lt;br /&gt;
A sample Apache configuration looks like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;Proxy balancer://oxcluster_docs&amp;gt;&lt;br /&gt;
    Order Deny,Allow&lt;br /&gt;
    Deny from all&lt;br /&gt;
    # configure the allowed IPs such that only the middleware nodes are able to access&lt;br /&gt;
    # the /documentconverterws endpoint must not be made available publicly!&lt;br /&gt;
    Allow from 10.0.1&lt;br /&gt;
    BalancerMember http://dc1:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC1&lt;br /&gt;
    BalancerMember http://dc2:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC2&lt;br /&gt;
    # add further converter nodes, as many as you have&lt;br /&gt;
    ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&lt;br /&gt;
    SetEnv proxy-initial-not-pooled&lt;br /&gt;
    SetEnv proxy-sendchunked&lt;br /&gt;
&amp;lt;/Proxy&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProxyPass /documentconverterws balancer://oxcluster_docs/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With that configuration in place, test the connectivity from the middleware node to that endpoint, e.g. (assuming the frontend node is called &amp;lt;code&amp;gt;frontend1&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://frontend1/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The response looks exactly like before. The difference is just that we access the service now via Apache.&lt;br /&gt;
&lt;br /&gt;
Execute the test multiple times. It must answer fast every time. If some answers are slow (maybe only once or twice) that is an indication that some route configuration was incorrect and Apache disabled some converter targets.&lt;br /&gt;
&lt;br /&gt;
Make sure you are actually getting responses from the different converter nodes by whatever means suit you (e.g. tcpdump on the converter nodes, looking at Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt; to verify all nodes show up as &amp;lt;code&amp;gt;Ok&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;Elected&amp;lt;/code&amp;gt; number increases equally for all converter nodes, etc.)&lt;br /&gt;
&lt;br /&gt;
Configure that endpoint in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle as described below and in particular make sure that in pop-out view all preview images are rendered correctly. That is the testcase for correct session stickyness.&lt;br /&gt;
&lt;br /&gt;
If everything works correctly, make sure the Apache configuration is adjusted accordingly on all your Apache / Fronted nodes.&lt;br /&gt;
&lt;br /&gt;
Now we have high availability for the converter nodes, but the Apache service is still a SPOF.&lt;br /&gt;
&lt;br /&gt;
== Third test: adding local HAproxy instances ==&lt;br /&gt;
&lt;br /&gt;
We add local HAproxy instances to eliminate the Apache SPOF.&lt;br /&gt;
&lt;br /&gt;
Assuming HAproxy is already running locally for other services. If not, install it and do a basic configuration according to [HAproxy].&lt;br /&gt;
&lt;br /&gt;
Add a stanza like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;listen converter&lt;br /&gt;
    mode              http&lt;br /&gt;
    option            dontlognull&lt;br /&gt;
    option            redispatch&lt;br /&gt;
    no option         httpclose&lt;br /&gt;
    timeout connect   10s&lt;br /&gt;
    timeout client    2m&lt;br /&gt;
    timeout server    2m&lt;br /&gt;
    bind 127.0.0.1:8008&lt;br /&gt;
    balance roundrobin&lt;br /&gt;
    option httpchk GET /documentconverterws&lt;br /&gt;
    server frontend1 frontend1:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    server frontend2 frontend2:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    # add more frontend nodes if you have them&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Re-test that also this listener works correctly.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://127.0.0.1:8008/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same as before, execute the test multiple times, and verify in the Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt;s that everything works as expected.&lt;br /&gt;
&lt;br /&gt;
Look at the HAproxy stats endpoint to verify all frontend nodes show as OK and get roughly the same number of sessions.&lt;br /&gt;
&lt;br /&gt;
If that looks good, configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle (as described below).&lt;br /&gt;
&lt;br /&gt;
== Final setup ==&lt;br /&gt;
&lt;br /&gt;
Assuming the test middleware node works as described in the previous section, do the same HAproxy configuration on all middleware nodes and configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in all middleware nodes' documenconverter-client configuration.&lt;br /&gt;
&lt;br /&gt;
The fully clustered setup should be working now.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
It is highly recommended to make sure you always end up on the same middleware node for testing, by whatever means is required in your infrastructure to do so. For this document we assume you can access them directly (internal testing). Otherwise you'd need to expose special entry points to your setup.&lt;br /&gt;
&lt;br /&gt;
If you can't ensure that, you need to configure all middleware nodes absolutely identical also during setup and testing, which is very cumbersome and error-prone.&lt;br /&gt;
&lt;br /&gt;
If you reconfigured something on the middleware node(s), restart the service there.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wipe out caches on the converter node(s) and restart the service there:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange-documentconverter-server stop&lt;br /&gt;
rm -rf /var/spool/open-xchange/documentconverter/readerengine.*/*&lt;br /&gt;
service open-xchange-documentconverter-server start&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Careful about your paths and when copy-pasting; I don't take responsibility of you remove something wrong.)&lt;br /&gt;
&lt;br /&gt;
If your testuser is logged in from a previous test, log out.&lt;br /&gt;
&lt;br /&gt;
Login your testuser.&lt;br /&gt;
&lt;br /&gt;
Access Drive. Upload test documents if not done before. Preferably some small trivial docs, also some large multi-page docs with embedded diagrams etc.&lt;br /&gt;
&lt;br /&gt;
Switch to &amp;quot;icons&amp;quot; or &amp;quot;tiles&amp;quot; view. You should get nice preview thumbnails for each document. (This is only a relevant test for the first time since the previews are stored in the database. TODO: find out how to wipe / re-test that.)&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;eye&amp;quot; icon to start the Document Viewer. You should be able to view documents with reasonable speed. Scrolling through the pages should be possible and fast.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;pop out&amp;quot; icon to the top right to use pop-out view. Verify all pages are rendered correctly in the full-page view and in the thumbnail previews.&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
In most of the times in our experiments if something was not working, it was a misconfiguration on network level. (Wrong hostnames, IPs, ports, missing firewall adjustments, etc).&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23839</id>
		<title>User:Dominik.epple/DocumentConverterInstall</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23839"/>
		<updated>2018-02-16T14:52:38Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrough.&lt;br /&gt;
&lt;br /&gt;
The other relevant documentation is to be considered as a reference.&lt;br /&gt;
&lt;br /&gt;
This document describes the fully clustered setup. Simpler setups can be deduced as special case.&lt;br /&gt;
&lt;br /&gt;
This document has been created and verified on CentOS7 and Debian Jessie, using OX App Suite 7.8.4.&lt;br /&gt;
&lt;br /&gt;
= Design description =&lt;br /&gt;
&lt;br /&gt;
We consider a clustered setup with multiple middleware nodes and multiple converter nodes.&lt;br /&gt;
&lt;br /&gt;
We consider a high available connection from the middleware nodes to the converter nodes realized using HAproxy instances running locally on the middleware nodes which do simple round-robin to the Apache instances of the Fronted nodes, which will do ''correct'' session stickyness aware routing to the converter nodes.&lt;br /&gt;
&lt;br /&gt;
We need the Apache instances to get correct ''session sticky'' routing behavior.&lt;br /&gt;
&lt;br /&gt;
We need the HAproxy instances to connect to the Apache instances in a high available fashion. If there are other means in the infrastructure offering that functionality, this is also okay. We present the HAproxy based setup to give an example of a fully working setup.&lt;br /&gt;
&lt;br /&gt;
= Software installation and configuration =&lt;br /&gt;
&lt;br /&gt;
Note: this guide is written distro-agnostic, so please use the distro's appropriate command for installing packages.&lt;br /&gt;
&lt;br /&gt;
Repos to be used are the standard repo definitions from https://software.open-xchange.com/products/.&lt;br /&gt;
&lt;br /&gt;
== Middleware nodes ==&lt;br /&gt;
&lt;br /&gt;
Prerequisites: Drive is installed and working. We need Drive to upload test documents and verify their conversion. This also assumes (since we are discussing a clustered setup) a clustered filestore is available and working. If you are only going for a single node proof-of-concept setup, that is not relevant of course.&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-api open-xchange-documentconverter-client&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/opt/open-xchange/etc/permissions.properties:&lt;br /&gt;
# assume a global switch on for testing. further config cascade stuff etc is out of scope&lt;br /&gt;
# of this document.&lt;br /&gt;
com.openexchange.capability.document_preview=true&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://host[:port]/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frontend nodes ==&lt;br /&gt;
&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
== Converter nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-server open-xchange-documentconverter-api readerengine&lt;br /&gt;
&lt;br /&gt;
(Note: the official documentation also mentions &amp;quot;pdf2svg&amp;quot; which at least on CentOS7 does not exist, but rather a package named &amp;quot;readerengine-pdf2svg&amp;quot; is pulled as dependency. So for the moment let's assume we don't need to install that explicitly, but if you are following this guide on Debian you should double-check.)&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/etc/server.properties:&lt;br /&gt;
 # Pick a unique route, which will be configured consistently in apache&lt;br /&gt;
 com.openexchange.server.backendRoute=DC1&lt;br /&gt;
 # Clustered setups need to listen not only on localhost&lt;br /&gt;
 com.openexchange.connector.networkListenerHost=*&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/documentconverter/etc/documentconverter.properties &lt;br /&gt;
 # TODO figure out the recommended Cache setup for a clustered scenario&lt;br /&gt;
 com.openexchange.documentconverter.RemoteCacheUrls = ?&lt;br /&gt;
 # Default is 3. Adjust for your sizing.&lt;br /&gt;
 com.openexchange.documentconverter.jobProcessorCount=3&lt;br /&gt;
&lt;br /&gt;
Services configuration:&lt;br /&gt;
&lt;br /&gt;
 systemctl start open-xchange-documentconverter-server&lt;br /&gt;
 systemctl enable open-xchange-documentconverter-server&lt;br /&gt;
&lt;br /&gt;
Note: you don't need ConfigDB / any DB access. Don't connect the converter nodes to any database. Don't make it join any Hazelcast cluster. No further configuration is required.&lt;br /&gt;
&lt;br /&gt;
If you are annoyed by the &amp;quot;unable to connect to ConfigDB&amp;quot; (false) error messages in the logs, you can configure logback to suppress them (TODO: add information how to do that).&lt;br /&gt;
&lt;br /&gt;
= Configure the middleware to converter connectivity =&lt;br /&gt;
&lt;br /&gt;
So that was the trivial part. Now it gets interesting.&lt;br /&gt;
&lt;br /&gt;
== First test: direct connectivity ==&lt;br /&gt;
&lt;br /&gt;
Pick a middleware node. Configure direct connection to one converter service which is called &amp;lt;code&amp;gt;dc1&amp;lt;/code&amp;gt;. By default the service listens on port &amp;lt;code&amp;gt;8008&amp;lt;/code&amp;gt; and listens on the path &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://dc1:8008/documentconverterws/&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In particular, you should see&lt;br /&gt;
&lt;br /&gt;
* HTTP status code 200 (not shown for clarity, but you can verify with &amp;lt;code&amp;gt;curl -v&amp;lt;/code&amp;gt;)&lt;br /&gt;
* &amp;lt;code&amp;gt;WebService is running...&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Error Code: 0&amp;quot;.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If that is successful, go ahead and configure that URL in the middleware node&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://dc1:8008/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do a testing cycle as described below.&lt;br /&gt;
&lt;br /&gt;
If everything works, you confirmed that the middleware node and the converter node are configured correctly.&lt;br /&gt;
&lt;br /&gt;
Now ensure all your middleware nodes and all your converter nodes are configured likewise. Make sure the converter nodes get unique &amp;lt;code&amp;gt;com.openexchange.server.backendRoute&amp;lt;/code&amp;gt; values (see above).&lt;br /&gt;
&lt;br /&gt;
== Second test: use Apache for loadbalancing ==&lt;br /&gt;
&lt;br /&gt;
Pick one frontend node to configure its Apache for loadbalancing for the converter nodes.&lt;br /&gt;
&lt;br /&gt;
There are sample configuration stanzas in our default configuration. They are just fine. Just make sure the &amp;lt;code&amp;gt;route&amp;lt;/code&amp;gt; parameters match the ones from the converter nodes.&lt;br /&gt;
&lt;br /&gt;
I want to emphasize to configure the &amp;lt;code&amp;gt;Allow&amp;lt;/code&amp;gt; line correctly. The &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt; endpoint must not be made available publicly!&lt;br /&gt;
&lt;br /&gt;
A sample Apache configuration looks like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;Proxy balancer://oxcluster_docs&amp;gt;&lt;br /&gt;
    Order Deny,Allow&lt;br /&gt;
    Deny from all&lt;br /&gt;
    # configure the allowed IPs such that only the middleware nodes are able to access&lt;br /&gt;
    # the /documentconverterws endpoint must not be made available publicly!&lt;br /&gt;
    Allow from 10.0.1&lt;br /&gt;
    BalancerMember http://dc1:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC1&lt;br /&gt;
    BalancerMember http://dc2:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC2&lt;br /&gt;
    # add further converter nodes, as many as you have&lt;br /&gt;
    ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&lt;br /&gt;
    SetEnv proxy-initial-not-pooled&lt;br /&gt;
    SetEnv proxy-sendchunked&lt;br /&gt;
&amp;lt;/Proxy&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProxyPass /documentconverterws balancer://oxcluster_docs/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With that configuration in place, test the connectivity from the middleware node to that endpoint, e.g. (assuming the frontend node is called &amp;lt;code&amp;gt;frontend1&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://frontend1/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The response looks exactly like before. The difference is just that we access the service now via Apache.&lt;br /&gt;
&lt;br /&gt;
Execute the test multiple times. It must answer fast every time. If some answers are slow (maybe only once or twice) that is an indication that some route configuration was incorrect and Apache disabled some converter targets.&lt;br /&gt;
&lt;br /&gt;
Make sure you are actually getting responses from the different converter nodes by whatever means suit you (e.g. tcpdump on the converter nodes, looking at Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt; to verify all nodes show up as &amp;lt;code&amp;gt;Ok&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;Elected&amp;lt;/code&amp;gt; number increases equally for all converter nodes, etc.)&lt;br /&gt;
&lt;br /&gt;
Configure that endpoint in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle as described below and in particular make sure that in pop-out view all preview images are rendered correctly. That is the testcase for correct session stickyness.&lt;br /&gt;
&lt;br /&gt;
If everything works correctly, make sure the Apache configuration is adjusted accordingly on all your Apache / Fronted nodes.&lt;br /&gt;
&lt;br /&gt;
Now we have high availability for the converter nodes, but the Apache service is still a SPOF.&lt;br /&gt;
&lt;br /&gt;
== Third test: adding local HAproxy instances ==&lt;br /&gt;
&lt;br /&gt;
We add local HAproxy instances to eliminate the Apache SPOF.&lt;br /&gt;
&lt;br /&gt;
Assuming HAproxy is already running locally for other services. If not, install it and do a basic configuration according to [HAproxy].&lt;br /&gt;
&lt;br /&gt;
Add a stanza like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;listen converter&lt;br /&gt;
    mode              http&lt;br /&gt;
    option            dontlognull&lt;br /&gt;
    option            redispatch&lt;br /&gt;
    no option         httpclose&lt;br /&gt;
    timeout connect   10s&lt;br /&gt;
    timeout client    2m&lt;br /&gt;
    timeout server    2m&lt;br /&gt;
    bind 127.0.0.1:8008&lt;br /&gt;
    balance roundrobin&lt;br /&gt;
    option httpchk GET /documentconverterws&lt;br /&gt;
    server frontend1 frontend1:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    server frontend2 frontend2:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    # add more frontend nodes if you have them&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Re-test that also this listener works correctly.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://127.0.0.1:8008/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same as before, execute the test multiple times, and verify in the Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt;s that everything works as expected.&lt;br /&gt;
&lt;br /&gt;
Look at the HAproxy stats endpoint to verify all frontend nodes show as OK and get roughly the same number of sessions.&lt;br /&gt;
&lt;br /&gt;
If that looks good, configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle (as described below).&lt;br /&gt;
&lt;br /&gt;
== Final setup ==&lt;br /&gt;
&lt;br /&gt;
Assuming the test middleware node works as described in the previous section, do the same HAproxy configuration on all middleware nodes and configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in all middleware nodes' middleware configuration.&lt;br /&gt;
&lt;br /&gt;
The fully clustered setup should be working now.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
It is highly recommended to make sure you always end up on the same middleware node for testing, by whatever means is required in your infrastructure to do so. For this document we assume you can access them directly (internal testing). Otherwise you'd need to expose special entry points to your setup.&lt;br /&gt;
&lt;br /&gt;
If you can't ensure that, you need to configure all middleware nodes absolutely identical also during setup and testing, which is very cumbersome and error-prone.&lt;br /&gt;
&lt;br /&gt;
If you reconfigured something on the middleware node(s), restart the service there.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wipe out caches on the converter node(s) and restart the service there:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange-documentconverter-server stop&lt;br /&gt;
rm -rf /var/spool/open-xchange/documentconverter/readerengine.*/*&lt;br /&gt;
service open-xchange-documentconverter-server start&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Careful about your paths and when copy-pasting; I don't take responsibility of you remove something wrong.)&lt;br /&gt;
&lt;br /&gt;
If your testuser is logged in from a previous test, log out.&lt;br /&gt;
&lt;br /&gt;
Login your testuser.&lt;br /&gt;
&lt;br /&gt;
Access Drive. Upload test documents if not done before. Preferably some small trivial docs, also some large multi-page docs with embedded diagrams etc.&lt;br /&gt;
&lt;br /&gt;
Switch to &amp;quot;icons&amp;quot; or &amp;quot;tiles&amp;quot; view. You should get nice preview thumbnails for each document. (This is only a relevant test for the first time since the previews are stored in the database. TODO: find out how to wipe / re-test that.)&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;eye&amp;quot; icon to start the Document Viewer. You should be able to view documents with reasonable speed. Scrolling through the pages should be possible and fast.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;pop out&amp;quot; icon to the top right to use pop-out view. Verify all pages are rendered correctly in the full-page view and in the thumbnail previews.&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
In most of the times in our experiments if something was not working, it was a misconfiguration on network level. (Wrong hostnames, IPs, ports, missing firewall adjustments, etc).&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/NFS4&amp;diff=23838</id>
		<title>User:Dominik.epple/NFS4</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/NFS4&amp;diff=23838"/>
		<updated>2018-02-16T11:49:51Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: Created page with &amp;quot;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;NFS4&amp;lt;/div&amp;gt;  __TOC__  = Overview =  While for production we nowadays nearly exclusively see Object Storage based setup, for POC setups it is still convenient...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;NFS4&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Overview =&lt;br /&gt;
&lt;br /&gt;
While for production we nowadays nearly exclusively see Object Storage based setup, for POC setups it is still convenient to use NFS as filestore. Smaller footprint, less efforts, functional and fast enough for some functional testing.&lt;br /&gt;
&lt;br /&gt;
However one disadvantage is that all NFS client machines need to have synchronized system userIDs in order for access to work, which is often not accounted for during initial setup and cumbersome to fix later.&lt;br /&gt;
&lt;br /&gt;
One possible approach is to use NFS4 with Kerberos as in that flavor access is not granted based on numerical userIDs, but rather symbolic usernames.&lt;br /&gt;
&lt;br /&gt;
The drawback of this solution is a slightly more complicated setup, but, once figured out how it works, it is surprisingly robust in first tests.&lt;br /&gt;
&lt;br /&gt;
== KDC setup ==&lt;br /&gt;
&lt;br /&gt;
Standard stuff, no special things.&lt;br /&gt;
&lt;br /&gt;
Initialize the stash.&lt;br /&gt;
&lt;br /&gt;
Create host keys for every host with host/hostname.fqdn and nfs/hostname.fqdn. Export to a keytab and transfer to NFS client as /etc/krb5.keytab.&lt;br /&gt;
&lt;br /&gt;
Create a kerberos principal for the open-xchange user. Probably a high (unlimited) ticket lifetime will be helpful.&lt;br /&gt;
&lt;br /&gt;
== NFS Server Setup ==&lt;br /&gt;
&lt;br /&gt;
Decide for a directory to export. In a standard setup with exported user homedirectories you can use the filestore/ subdirectory of the open-xchange users home directory.&lt;br /&gt;
&lt;br /&gt;
Standard linux practice is to bindmount that under some /export toplevel export point.&lt;br /&gt;
&lt;br /&gt;
/etc/exports file:&lt;br /&gt;
&lt;br /&gt;
 /export kclient.lan(rw,fsid=0,sec=krb5i)&lt;br /&gt;
&lt;br /&gt;
CentOS 7:&lt;br /&gt;
&lt;br /&gt;
 yum install nfs-utils&lt;br /&gt;
&lt;br /&gt;
 systemctl restart nfs&lt;br /&gt;
 systemctl enable nfs&lt;br /&gt;
&lt;br /&gt;
 systemctl restart nfs-secure&lt;br /&gt;
 systemctl enable nfs-secure&lt;br /&gt;
&lt;br /&gt;
== NFS Client Setup ==&lt;br /&gt;
&lt;br /&gt;
CentOS7:&lt;br /&gt;
&lt;br /&gt;
 systemctl restart nfs-secure&lt;br /&gt;
 systemctl enable nfs-secure&lt;br /&gt;
&lt;br /&gt;
 mount -t nfs4 -o sec=krb5i knfs:/ /mnt&lt;br /&gt;
&lt;br /&gt;
== Service Setup ==&lt;br /&gt;
&lt;br /&gt;
For accessing data, the OX service needs a kerberos ticket.&lt;br /&gt;
&lt;br /&gt;
 # su - open-xchange&lt;br /&gt;
 $ kinit&lt;br /&gt;
&lt;br /&gt;
That is somewhat clumsy (TODO: find out how to automate that).&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23837</id>
		<title>User:Dominik.epple/DocumentConverterInstall</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23837"/>
		<updated>2018-02-16T09:46:30Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Troubleshooting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrough.&lt;br /&gt;
&lt;br /&gt;
The other relevant documentation is to be considered as a reference.&lt;br /&gt;
&lt;br /&gt;
This document describes the fully clustered setup. Simpler setups can be deduced as special case.&lt;br /&gt;
&lt;br /&gt;
This document has been created and verified on CentOS7 and OX App Suite 7.8.4.&lt;br /&gt;
&lt;br /&gt;
= Design description =&lt;br /&gt;
&lt;br /&gt;
We consider a clustered setup with multiple middleware nodes and multiple converter nodes.&lt;br /&gt;
&lt;br /&gt;
We consider a high available connection from the middleware nodes to the converter nodes realized using HAproxy instances running locally on the middleware nodes which do simple round-robin to the Apache instances of the Fronted nodes, which will do ''correct'' session stickyness aware routing to the converter nodes.&lt;br /&gt;
&lt;br /&gt;
We need the Apache instances to get correct ''session sticky'' routing behavior.&lt;br /&gt;
&lt;br /&gt;
We need the HAproxy instances to connect to the Apache instances in a high available fashion. If there are other means in the infrastructure offering that functionality, this is also okay. We present the HAproxy based setup to give an example of a fully working setup.&lt;br /&gt;
&lt;br /&gt;
= Software installation and configuration =&lt;br /&gt;
&lt;br /&gt;
== Middleware nodes ==&lt;br /&gt;
&lt;br /&gt;
Prerequisites: Drive is installed and working. We need Drive to upload test documents and verify their conversion. This also assumes (since we a discussing a clustered setup) a clustered filestore is available and working. If you are only going for a single node proof-of-concept setup, that is not relevant of course.&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-api open-xchange-documentconverter-client&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/opt/open-xchange/etc/permissions.properties:&lt;br /&gt;
# assume a global switch on for testing. further config cascade stuff etc is out of scope&lt;br /&gt;
# of this document.&lt;br /&gt;
com.openexchange.capability.document_preview=true&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://host[:port]/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frontend nodes ==&lt;br /&gt;
&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
== Converter nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-server open-xchange-documentconverter-api readerengine&lt;br /&gt;
&lt;br /&gt;
(Note: the official documentation also mentions &amp;quot;pdf2svg&amp;quot; which at least on CentOS7 does not exist, but rather a package named &amp;quot;readerengine-pdf2svg&amp;quot; is pulled as dependency. So for the moment let's assume we don't need to install that explicitly, but if you are following this guide on Debian you should double-check.)&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/etc/server.properties:&lt;br /&gt;
 # Pick a unique route, which will be configured consistently in apache&lt;br /&gt;
 com.openexchange.server.backendRoute=DC1&lt;br /&gt;
 # Clustered setups need to listen not only on localhost&lt;br /&gt;
 com.openexchange.connector.networkListenerHost=*&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/documentconverter/etc/documentconverter.properties &lt;br /&gt;
 # TODO figure out the recommended Cache setup for a clustered scenario&lt;br /&gt;
 com.openexchange.documentconverter.RemoteCacheUrls = ?&lt;br /&gt;
 # Default is 3. Adjust for your sizing.&lt;br /&gt;
 com.openexchange.documentconverter.jobProcessorCount=3&lt;br /&gt;
&lt;br /&gt;
Services configuration:&lt;br /&gt;
&lt;br /&gt;
 systemctl start open-xchange-documentconverter-server&lt;br /&gt;
 systemctl enable open-xchange-documentconverter-server&lt;br /&gt;
&lt;br /&gt;
Note: you don't need ConfigDB / any DB access. Don't connect the converter nodes to any database. Don't make it join any Hazelcast cluster. No further configuration is required.&lt;br /&gt;
&lt;br /&gt;
If you are annoyed by the &amp;quot;unable to connect to ConfigDB&amp;quot; (false) error messages in the logs, you can configure logback to suppress them (TODO: add information how to do that).&lt;br /&gt;
&lt;br /&gt;
= Configure the middleware to converter connectivity =&lt;br /&gt;
&lt;br /&gt;
So that was the trivial part. Now it gets interesting.&lt;br /&gt;
&lt;br /&gt;
== First test: direct connectivity ==&lt;br /&gt;
&lt;br /&gt;
Pick a middleware node. Configure direct connection to one converter service which is called &amp;lt;code&amp;gt;dc1&amp;lt;/code&amp;gt;. By default the service listens on port &amp;lt;code&amp;gt;8008&amp;lt;/code&amp;gt; and listens on the path &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://dc1:8008/documentconverterws/&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's how it should look like. HTTP status code 200 (not shown for clarity, but you can verify with curl -v, &amp;quot;WebService is running...&amp;quot;, &amp;quot;Error Code: 0&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If that is successful, go ahead and configure that URL in the middleware node&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://dc1:8008/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do a testing cycle as described below.&lt;br /&gt;
&lt;br /&gt;
If everything works, you confirmed that the middleware node and the converter node are configured correctly.&lt;br /&gt;
&lt;br /&gt;
Now ensure all your middleware nodes and all your converter nodes are configured likewise. Make sure the converter nodes get unique &amp;lt;code&amp;gt;com.openexchange.server.backendRoute&amp;lt;/code&amp;gt; values (see above).&lt;br /&gt;
&lt;br /&gt;
== Second test: use Apache for loadbalancing ==&lt;br /&gt;
&lt;br /&gt;
Pick one frontend node to configure its Apache for loadbalancing for the converter nodes.&lt;br /&gt;
&lt;br /&gt;
There are sample configuration stanzas in our default configuration. They are just fine. Just make sure the &amp;lt;code&amp;gt;route&amp;lt;/code&amp;gt; parameters match the ones from the converter nodes.&lt;br /&gt;
&lt;br /&gt;
I want to emphasize to configure the &amp;lt;code&amp;gt;Allow&amp;lt;/code&amp;gt; line correctly. The &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt; endpoint must not be made available publicly!&lt;br /&gt;
&lt;br /&gt;
A sample Apache configuration looks like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;Proxy balancer://oxcluster_docs&amp;gt;&lt;br /&gt;
    Order Deny,Allow&lt;br /&gt;
    Deny from all&lt;br /&gt;
    # configure the allowed IPs such that only the middleware nodes are able to access&lt;br /&gt;
    # the /documentconverterws endpoint must not be made available publicly!&lt;br /&gt;
    Allow from 10.0.1&lt;br /&gt;
    BalancerMember http://dc1:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC1&lt;br /&gt;
    BalancerMember http://dc2:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC2&lt;br /&gt;
    # add further converter nodes, as many as you have&lt;br /&gt;
    ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&lt;br /&gt;
    SetEnv proxy-initial-not-pooled&lt;br /&gt;
    SetEnv proxy-sendchunked&lt;br /&gt;
&amp;lt;/Proxy&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProxyPass /documentconverterws balancer://oxcluster_docs/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With that configuration in place, test the connectivity from the middleware node to that endpoint, e.g. (assuming the frontend node is called &amp;lt;code&amp;gt;frontend1&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://frontend1/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The response looks exactly like before. The difference is just that we access the service now via Apache.&lt;br /&gt;
&lt;br /&gt;
Execute the test multiple times. It must answer fast every time. If some answers are slow (maybe only once or twice) that is an indication that some route configuration was incorrect and Apache disabled some converter targets.&lt;br /&gt;
&lt;br /&gt;
Make sure you are actually getting responses from the different converter nodes by whatever means suit you (e.g. tcpdump on the converter nodes, looking at Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt; to verify all nodes show up as &amp;lt;code&amp;gt;Ok&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;Elected&amp;lt;/code&amp;gt; number increases equally for all converter nodes, etc.)&lt;br /&gt;
&lt;br /&gt;
Configure that endpoint in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle as described below and in particular make sure that in pop-out view all preview images are rendered correctly. That is the testcase for correct session stickyness.&lt;br /&gt;
&lt;br /&gt;
If everything works correctly, make sure the Apache configuration is adjusted accordingly on all your Apache / Fronted nodes.&lt;br /&gt;
&lt;br /&gt;
Now we have high availability for the converter nodes, but the Apache service is still a SPOF.&lt;br /&gt;
&lt;br /&gt;
== Third test: adding local HAproxy instances ==&lt;br /&gt;
&lt;br /&gt;
We add local HAproxy instances to eliminate the Apache SPOF.&lt;br /&gt;
&lt;br /&gt;
Assuming HAproxy is already running locally for other services. If not, install it and do a basic configuration according to [HAproxy].&lt;br /&gt;
&lt;br /&gt;
Add a stanza like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;listen converter&lt;br /&gt;
    mode              http&lt;br /&gt;
    option            dontlognull&lt;br /&gt;
    option            redispatch&lt;br /&gt;
    no option         httpclose&lt;br /&gt;
    timeout connect   10s&lt;br /&gt;
    timeout client    2m&lt;br /&gt;
    timeout server    2m&lt;br /&gt;
    bind 127.0.0.1:8008&lt;br /&gt;
    balance roundrobin&lt;br /&gt;
    option httpchk GET /documentconverterws&lt;br /&gt;
    server frontend1 frontend1:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    server frontend2 frontend2:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    # add more frontend nodes if you have them&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Re-test that also this listener works correctly.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://127.0.0.1:8008/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same as before, execute the test multiple times, and verify in the Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt;s that everything works as expected.&lt;br /&gt;
&lt;br /&gt;
Look at the HAproxy stats endpoint to verify all frontend nodes show as OK and get roughly the same number of sessions.&lt;br /&gt;
&lt;br /&gt;
If that looks good, configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle (as described below).&lt;br /&gt;
&lt;br /&gt;
== Final setup ==&lt;br /&gt;
&lt;br /&gt;
Assuming the test middleware node works as described in the previous section, do the same HAproxy configuration on all middleware nodes and configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in all middleware nodes' middleware configuration.&lt;br /&gt;
&lt;br /&gt;
The fully clustered setup should be working now.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
It is highly recommended to make sure you always end up on the same middleware node for testing, by whatever means is required in your infrastructure to do so. For this document we assume you can access them directly (internal testing). Otherwise you'd need to expose special entry points to your setup.&lt;br /&gt;
&lt;br /&gt;
If you can't ensure that, you need to configure all middleware nodes absolutely identical also during setup and testing, which is very cumbersome and error-prone.&lt;br /&gt;
&lt;br /&gt;
If you reconfigured something on the middleware node(s), restart the service there.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wipe out caches on the converter node(s) and restart the service there:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange-documentconverter-server stop&lt;br /&gt;
rm -rf /var/spool/open-xchange/documentconverter/readerengine.*/*&lt;br /&gt;
service open-xchange-documentconverter-server start&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Careful about your paths and when copy-pasting; I don't take responsibility of you remove something wrong.)&lt;br /&gt;
&lt;br /&gt;
If your testuser is logged in from a previous test, log out.&lt;br /&gt;
&lt;br /&gt;
Login your testuser.&lt;br /&gt;
&lt;br /&gt;
Access Drive. Upload test documents if not done before. Preferably some small trivial docs, also some large multi-page docs with embedded diagrams etc.&lt;br /&gt;
&lt;br /&gt;
Switch to &amp;quot;icons&amp;quot; or &amp;quot;tiles&amp;quot; view. You should get nice preview thumbnails for each document. (This is only a relevant test for the first time since the previews are stored in the database. TODO: find out how to wipe / re-test that.)&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;eye&amp;quot; icon to start the Document Viewer. You should be able to view documents with reasonable speed. Scrolling through the pages should be possible and fast.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;pop out&amp;quot; icon to the top right to use pop-out view. Verify all pages are rendered correctly in the full-page view and in the thumbnail previews.&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
In most of the times in our experiments if something was not working, it was a misconfiguration on network level. (Wrong hostnames, IPs, ports, missing firewall adjustments, etc).&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23836</id>
		<title>User:Dominik.epple/DocumentConverterInstall</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23836"/>
		<updated>2018-02-16T09:37:25Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrough.&lt;br /&gt;
&lt;br /&gt;
The other relevant documentation is to be considered as a reference.&lt;br /&gt;
&lt;br /&gt;
This document describes the fully clustered setup. Simpler setups can be deduced as special case.&lt;br /&gt;
&lt;br /&gt;
This document has been created and verified on CentOS7 and OX App Suite 7.8.4.&lt;br /&gt;
&lt;br /&gt;
= Design description =&lt;br /&gt;
&lt;br /&gt;
We consider a clustered setup with multiple middleware nodes and multiple converter nodes.&lt;br /&gt;
&lt;br /&gt;
We consider a high available connection from the middleware nodes to the converter nodes realized using HAproxy instances running locally on the middleware nodes which do simple round-robin to the Apache instances of the Fronted nodes, which will do ''correct'' session stickyness aware routing to the converter nodes.&lt;br /&gt;
&lt;br /&gt;
We need the Apache instances to get correct ''session sticky'' routing behavior.&lt;br /&gt;
&lt;br /&gt;
We need the HAproxy instances to connect to the Apache instances in a high available fashion. If there are other means in the infrastructure offering that functionality, this is also okay. We present the HAproxy based setup to give an example of a fully working setup.&lt;br /&gt;
&lt;br /&gt;
= Software installation and configuration =&lt;br /&gt;
&lt;br /&gt;
== Middleware nodes ==&lt;br /&gt;
&lt;br /&gt;
Prerequisites: Drive is installed and working. We need Drive to upload test documents and verify their conversion. This also assumes (since we a discussing a clustered setup) a clustered filestore is available and working. If you are only going for a single node proof-of-concept setup, that is not relevant of course.&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-api open-xchange-documentconverter-client&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/opt/open-xchange/etc/permissions.properties:&lt;br /&gt;
# assume a global switch on for testing. further config cascade stuff etc is out of scope&lt;br /&gt;
# of this document.&lt;br /&gt;
com.openexchange.capability.document_preview=true&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://host[:port]/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frontend nodes ==&lt;br /&gt;
&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
== Converter nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-server open-xchange-documentconverter-api readerengine&lt;br /&gt;
&lt;br /&gt;
(Note: the official documentation also mentions &amp;quot;pdf2svg&amp;quot; which at least on CentOS7 does not exist, but rather a package named &amp;quot;readerengine-pdf2svg&amp;quot; is pulled as dependency. So for the moment let's assume we don't need to install that explicitly, but if you are following this guide on Debian you should double-check.)&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/etc/server.properties:&lt;br /&gt;
 # Pick a unique route, which will be configured consistently in apache&lt;br /&gt;
 com.openexchange.server.backendRoute=DC1&lt;br /&gt;
 # Clustered setups need to listen not only on localhost&lt;br /&gt;
 com.openexchange.connector.networkListenerHost=*&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/documentconverter/etc/documentconverter.properties &lt;br /&gt;
 # TODO figure out the recommended Cache setup for a clustered scenario&lt;br /&gt;
 com.openexchange.documentconverter.RemoteCacheUrls = ?&lt;br /&gt;
 # Default is 3. Adjust for your sizing.&lt;br /&gt;
 com.openexchange.documentconverter.jobProcessorCount=3&lt;br /&gt;
&lt;br /&gt;
Services configuration:&lt;br /&gt;
&lt;br /&gt;
 systemctl start open-xchange-documentconverter-server&lt;br /&gt;
 systemctl enable open-xchange-documentconverter-server&lt;br /&gt;
&lt;br /&gt;
Note: you don't need ConfigDB / any DB access. Don't connect the converter nodes to any database. Don't make it join any Hazelcast cluster. No further configuration is required.&lt;br /&gt;
&lt;br /&gt;
If you are annoyed by the &amp;quot;unable to connect to ConfigDB&amp;quot; (false) error messages in the logs, you can configure logback to suppress them (TODO: add information how to do that).&lt;br /&gt;
&lt;br /&gt;
= Configure the middleware to converter connectivity =&lt;br /&gt;
&lt;br /&gt;
So that was the trivial part. Now it gets interesting.&lt;br /&gt;
&lt;br /&gt;
== First test: direct connectivity ==&lt;br /&gt;
&lt;br /&gt;
Pick a middleware node. Configure direct connection to one converter service which is called &amp;lt;code&amp;gt;dc1&amp;lt;/code&amp;gt;. By default the service listens on port &amp;lt;code&amp;gt;8008&amp;lt;/code&amp;gt; and listens on the path &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://dc1:8008/documentconverterws/&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's how it should look like. HTTP status code 200 (not shown for clarity, but you can verify with curl -v, &amp;quot;WebService is running...&amp;quot;, &amp;quot;Error Code: 0&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If that is successful, go ahead and configure that URL in the middleware node&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://dc1:8008/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do a testing cycle as described below.&lt;br /&gt;
&lt;br /&gt;
If everything works, you confirmed that the middleware node and the converter node are configured correctly.&lt;br /&gt;
&lt;br /&gt;
Now ensure all your middleware nodes and all your converter nodes are configured likewise. Make sure the converter nodes get unique &amp;lt;code&amp;gt;com.openexchange.server.backendRoute&amp;lt;/code&amp;gt; values (see above).&lt;br /&gt;
&lt;br /&gt;
== Second test: use Apache for loadbalancing ==&lt;br /&gt;
&lt;br /&gt;
Pick one frontend node to configure its Apache for loadbalancing for the converter nodes.&lt;br /&gt;
&lt;br /&gt;
There are sample configuration stanzas in our default configuration. They are just fine. Just make sure the &amp;lt;code&amp;gt;route&amp;lt;/code&amp;gt; parameters match the ones from the converter nodes.&lt;br /&gt;
&lt;br /&gt;
I want to emphasize to configure the &amp;lt;code&amp;gt;Allow&amp;lt;/code&amp;gt; line correctly. The &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt; endpoint must not be made available publicly!&lt;br /&gt;
&lt;br /&gt;
A sample Apache configuration looks like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;Proxy balancer://oxcluster_docs&amp;gt;&lt;br /&gt;
    Order Deny,Allow&lt;br /&gt;
    Deny from all&lt;br /&gt;
    # configure the allowed IPs such that only the middleware nodes are able to access&lt;br /&gt;
    # the /documentconverterws endpoint must not be made available publicly!&lt;br /&gt;
    Allow from 10.0.1&lt;br /&gt;
    BalancerMember http://dc1:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC1&lt;br /&gt;
    BalancerMember http://dc2:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC2&lt;br /&gt;
    # add further converter nodes, as many as you have&lt;br /&gt;
    ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&lt;br /&gt;
    SetEnv proxy-initial-not-pooled&lt;br /&gt;
    SetEnv proxy-sendchunked&lt;br /&gt;
&amp;lt;/Proxy&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProxyPass /documentconverterws balancer://oxcluster_docs/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With that configuration in place, test the connectivity from the middleware node to that endpoint, e.g. (assuming the frontend node is called &amp;lt;code&amp;gt;frontend1&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://frontend1/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The response looks exactly like before. The difference is just that we access the service now via Apache.&lt;br /&gt;
&lt;br /&gt;
Execute the test multiple times. It must answer fast every time. If some answers are slow (maybe only once or twice) that is an indication that some route configuration was incorrect and Apache disabled some converter targets.&lt;br /&gt;
&lt;br /&gt;
Make sure you are actually getting responses from the different converter nodes by whatever means suit you (e.g. tcpdump on the converter nodes, looking at Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt; to verify all nodes show up as &amp;lt;code&amp;gt;Ok&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;Elected&amp;lt;/code&amp;gt; number increases equally for all converter nodes, etc.)&lt;br /&gt;
&lt;br /&gt;
Configure that endpoint in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle as described below and in particular make sure that in pop-out view all preview images are rendered correctly. That is the testcase for correct session stickyness.&lt;br /&gt;
&lt;br /&gt;
If everything works correctly, make sure the Apache configuration is adjusted accordingly on all your Apache / Fronted nodes.&lt;br /&gt;
&lt;br /&gt;
Now we have high availability for the converter nodes, but the Apache service is still a SPOF.&lt;br /&gt;
&lt;br /&gt;
== Third test: adding local HAproxy instances ==&lt;br /&gt;
&lt;br /&gt;
We add local HAproxy instances to eliminate the Apache SPOF.&lt;br /&gt;
&lt;br /&gt;
Assuming HAproxy is already running locally for other services. If not, install it and do a basic configuration according to [HAproxy].&lt;br /&gt;
&lt;br /&gt;
Add a stanza like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;listen converter&lt;br /&gt;
    mode              http&lt;br /&gt;
    option            dontlognull&lt;br /&gt;
    option            redispatch&lt;br /&gt;
    no option         httpclose&lt;br /&gt;
    timeout connect   10s&lt;br /&gt;
    timeout client    2m&lt;br /&gt;
    timeout server    2m&lt;br /&gt;
    bind 127.0.0.1:8008&lt;br /&gt;
    balance roundrobin&lt;br /&gt;
    option httpchk GET /documentconverterws&lt;br /&gt;
    server frontend1 frontend1:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    server frontend2 frontend2:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    # add more frontend nodes if you have them&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Re-test that also this listener works correctly.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://127.0.0.1:8008/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same as before, execute the test multiple times, and verify in the Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt;s that everything works as expected.&lt;br /&gt;
&lt;br /&gt;
Look at the HAproxy stats endpoint to verify all frontend nodes show as OK and get roughly the same number of sessions.&lt;br /&gt;
&lt;br /&gt;
If that looks good, configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle (as described below).&lt;br /&gt;
&lt;br /&gt;
== Final setup ==&lt;br /&gt;
&lt;br /&gt;
Assuming the test middleware node works as described in the previous section, do the same HAproxy configuration on all middleware nodes and configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in all middleware nodes' middleware configuration.&lt;br /&gt;
&lt;br /&gt;
The fully clustered setup should be working now.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
It is highly recommended to make sure you always end up on the same middleware node for testing, by whatever means is required in your infrastructure to do so. For this document we assume you can access them directly (internal testing). Otherwise you'd need to expose special entry points to your setup.&lt;br /&gt;
&lt;br /&gt;
If you can't ensure that, you need to configure all middleware nodes absolutely identical also during setup and testing, which is very cumbersome and error-prone.&lt;br /&gt;
&lt;br /&gt;
If you reconfigured something on the middleware node(s), restart the service there.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wipe out caches on the converter node(s) and restart the service there:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange-documentconverter-server stop&lt;br /&gt;
rm -rf /var/spool/open-xchange/documentconverter/readerengine.*/*&lt;br /&gt;
service open-xchange-documentconverter-server start&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Careful about your paths and when copy-pasting; I don't take responsibility of you remove something wrong.)&lt;br /&gt;
&lt;br /&gt;
If your testuser is logged in from a previous test, log out.&lt;br /&gt;
&lt;br /&gt;
Login your testuser.&lt;br /&gt;
&lt;br /&gt;
Access Drive. Upload test documents if not done before. Preferably some small trivial docs, also some large multi-page docs with embedded diagrams etc.&lt;br /&gt;
&lt;br /&gt;
Switch to &amp;quot;icons&amp;quot; or &amp;quot;tiles&amp;quot; view. You should get nice preview thumbnails for each document. (This is only a relevant test for the first time since the previews are stored in the database. TODO: find out how to wipe / re-test that.)&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;eye&amp;quot; icon to start the Document Viewer. You should be able to view documents with reasonable speed. Scrolling through the pages should be possible and fast.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;pop out&amp;quot; icon to the top right to use pop-out view. Verify all pages are rendered correctly in the full-page view and in the thumbnail previews.&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
In most of the times in our experiments if something was not working, it was a misconfiguration on network level. (Wrong hostnames, IPs, ports, missing firewall adjustments, etc).&lt;br /&gt;
&lt;br /&gt;
The documentconverter service&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23835</id>
		<title>User:Dominik.epple/DocumentConverterInstall</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23835"/>
		<updated>2018-02-16T09:37:08Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrough.&lt;br /&gt;
&lt;br /&gt;
The other relevant documentation is to be considered as a reference.&lt;br /&gt;
&lt;br /&gt;
This document describes the fully clustered setup. Simpler setups can be deduced as special case.&lt;br /&gt;
&lt;br /&gt;
This document has been created and verified on CentOS7 and OX App Suite 7.8.4.&lt;br /&gt;
&lt;br /&gt;
= Design description =&lt;br /&gt;
&lt;br /&gt;
We consider a clustered setup with multiple middleware nodes and multiple converter nodes.&lt;br /&gt;
&lt;br /&gt;
We consider a high available connection from the middleware nodes to the converter nodes realized using HAproxy instances running locally on the middleware nodes which do simple round-robin to the Apache instances of the Fronted nodes, which will do ''correct'' session stickyness aware routing to the converter nodes.&lt;br /&gt;
&lt;br /&gt;
We need the Apache instances to get correct ''session sticky'' routing behavior.&lt;br /&gt;
&lt;br /&gt;
We need the HAproxy instances to connect to the Apache instances in a high available fashion. If there are other means in the infrastructure offering that functionality, this is also okay. We present the HAproxy based setup to give an example of a fully working setup.&lt;br /&gt;
&lt;br /&gt;
= Software installation and configuration =&lt;br /&gt;
&lt;br /&gt;
== Middleware nodes ==&lt;br /&gt;
&lt;br /&gt;
Prerequisites: Drive is installed and working. We need Drive to upload test documents and verify their conversion. This also assumes (since we a discussing a clustered setup) a clustered filestore is available and working. If you are only going for a single node proof-of-concept setup, that is not relevant of course.&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-api open-xchange-documentconverter-client&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/opt/open-xchange/etc/permissions.properties:&lt;br /&gt;
# assume a global switch on for testing. further config cascade stuff etc is out of scope&lt;br /&gt;
# of this document.&lt;br /&gt;
com.openexchange.capability.document_preview=true&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://host[:port]/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frontend nodes ==&lt;br /&gt;
&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
== Converter nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-server open-xchange-documentconverter-api readerengine&lt;br /&gt;
&lt;br /&gt;
(Note: the official documentation also mentions &amp;quot;pdf2svg&amp;quot; which at least on CentOS7 does not exist, but rather a package named &amp;quot;readerengine-pdf2svg&amp;quot; is pulled as dependency. So for the moment let's assume we don't need to install that explicitly, but if you are following this guide on Debian you should double-check.)&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/etc/server.properties:&lt;br /&gt;
 # Pick a unique route, which will be configured consistently in apache&lt;br /&gt;
 com.openexchange.server.backendRoute=DC1&lt;br /&gt;
 # Clustered setups need to listen not only on localhost&lt;br /&gt;
 com.openexchange.connector.networkListenerHost=*&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/documentconverter/etc/documentconverter.properties &lt;br /&gt;
 # TODO figure out the recommended Cache setup for a clustered scenario&lt;br /&gt;
 com.openexchange.documentconverter.RemoteCacheUrls = ?&lt;br /&gt;
 # Default is 3. Adjust for your sizing.&lt;br /&gt;
 com.openexchange.documentconverter.jobProcessorCount=3&lt;br /&gt;
&lt;br /&gt;
Services configuration:&lt;br /&gt;
&lt;br /&gt;
 systemctl start open-xchange-documentconverter-server&lt;br /&gt;
 systemctl enable open-xchange-documentconverter-server&lt;br /&gt;
&lt;br /&gt;
Note: you don't need ConfigDB / any DB access. Don't connect the converter nodes to any database. Don't make it join any Hazelcast cluster. No further configuration is required.&lt;br /&gt;
&lt;br /&gt;
If you are annoyed by the &amp;quot;unable to connect to ConfigDB&amp;quot; (false) error messages in the logs, you can configure logback to suppress them (TODO: add information how to do that).&lt;br /&gt;
&lt;br /&gt;
= Configure the middleware to converter connectivity =&lt;br /&gt;
&lt;br /&gt;
So that was the trivial part. Now it gets interesting.&lt;br /&gt;
&lt;br /&gt;
== First test: direct connectivity ==&lt;br /&gt;
&lt;br /&gt;
Pick a middleware node. Configure direct connection to one converter service which is called &amp;lt;code&amp;gt;dc1&amp;lt;/code&amp;gt;. By default the service listens on port &amp;lt;code&amp;gt;8008&amp;lt;/code&amp;gt; and listens on the path &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://dc1:8008/documentconverterws/&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's how it should look like. HTTP status code 200 (not shown for clarity, but you can verify with curl -v, &amp;quot;WebService is running...&amp;quot;, &amp;quot;Error Code: 0&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If that is successful, go ahead and configure that URL in the middleware node&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://dc1:8008/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do a testing cycle as described below.&lt;br /&gt;
&lt;br /&gt;
If everything works, you confirmed that the middleware node and the converter node are configured correctly.&lt;br /&gt;
&lt;br /&gt;
Now ensure all your middleware nodes and all your converter nodes are configured likewise. Make sure the converter nodes get unique &amp;lt;code&amp;gt;com.openexchange.server.backendRoute&amp;lt;/code&amp;gt; values (see above).&lt;br /&gt;
&lt;br /&gt;
= Second test: use Apache for loadbalancing =&lt;br /&gt;
&lt;br /&gt;
Pick one frontend node to configure its Apache for loadbalancing for the converter nodes.&lt;br /&gt;
&lt;br /&gt;
There are sample configuration stanzas in our default configuration. They are just fine. Just make sure the &amp;lt;code&amp;gt;route&amp;lt;/code&amp;gt; parameters match the ones from the converter nodes.&lt;br /&gt;
&lt;br /&gt;
I want to emphasize to configure the &amp;lt;code&amp;gt;Allow&amp;lt;/code&amp;gt; line correctly. The &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt; endpoint must not be made available publicly!&lt;br /&gt;
&lt;br /&gt;
A sample Apache configuration looks like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;Proxy balancer://oxcluster_docs&amp;gt;&lt;br /&gt;
    Order Deny,Allow&lt;br /&gt;
    Deny from all&lt;br /&gt;
    # configure the allowed IPs such that only the middleware nodes are able to access&lt;br /&gt;
    # the /documentconverterws endpoint must not be made available publicly!&lt;br /&gt;
    Allow from 10.0.1&lt;br /&gt;
    BalancerMember http://dc1:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC1&lt;br /&gt;
    BalancerMember http://dc2:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC2&lt;br /&gt;
    # add further converter nodes, as many as you have&lt;br /&gt;
    ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&lt;br /&gt;
    SetEnv proxy-initial-not-pooled&lt;br /&gt;
    SetEnv proxy-sendchunked&lt;br /&gt;
&amp;lt;/Proxy&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProxyPass /documentconverterws balancer://oxcluster_docs/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With that configuration in place, test the connectivity from the middleware node to that endpoint, e.g. (assuming the frontend node is called &amp;lt;code&amp;gt;frontend1&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://frontend1/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The response looks exactly like before. The difference is just that we access the service now via Apache.&lt;br /&gt;
&lt;br /&gt;
Execute the test multiple times. It must answer fast every time. If some answers are slow (maybe only once or twice) that is an indication that some route configuration was incorrect and Apache disabled some converter targets.&lt;br /&gt;
&lt;br /&gt;
Make sure you are actually getting responses from the different converter nodes by whatever means suit you (e.g. tcpdump on the converter nodes, looking at Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt; to verify all nodes show up as &amp;lt;code&amp;gt;Ok&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;Elected&amp;lt;/code&amp;gt; number increases equally for all converter nodes, etc.)&lt;br /&gt;
&lt;br /&gt;
Configure that endpoint in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle as described below and in particular make sure that in pop-out view all preview images are rendered correctly. That is the testcase for correct session stickyness.&lt;br /&gt;
&lt;br /&gt;
If everything works correctly, make sure the Apache configuration is adjusted accordingly on all your Apache / Fronted nodes.&lt;br /&gt;
&lt;br /&gt;
Now we have high availability for the converter nodes, but the Apache service is still a SPOF.&lt;br /&gt;
&lt;br /&gt;
== Third test: adding local HAproxy instances ==&lt;br /&gt;
&lt;br /&gt;
We add local HAproxy instances to eliminate the Apache SPOF.&lt;br /&gt;
&lt;br /&gt;
Assuming HAproxy is already running locally for other services. If not, install it and do a basic configuration according to [HAproxy].&lt;br /&gt;
&lt;br /&gt;
Add a stanza like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;listen converter&lt;br /&gt;
    mode              http&lt;br /&gt;
    option            dontlognull&lt;br /&gt;
    option            redispatch&lt;br /&gt;
    no option         httpclose&lt;br /&gt;
    timeout connect   10s&lt;br /&gt;
    timeout client    2m&lt;br /&gt;
    timeout server    2m&lt;br /&gt;
    bind 127.0.0.1:8008&lt;br /&gt;
    balance roundrobin&lt;br /&gt;
    option httpchk GET /documentconverterws&lt;br /&gt;
    server frontend1 frontend1:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    server frontend2 frontend2:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    # add more frontend nodes if you have them&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Re-test that also this listener works correctly.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://127.0.0.1:8008/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same as before, execute the test multiple times, and verify in the Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt;s that everything works as expected.&lt;br /&gt;
&lt;br /&gt;
Look at the HAproxy stats endpoint to verify all frontend nodes show as OK and get roughly the same number of sessions.&lt;br /&gt;
&lt;br /&gt;
If that looks good, configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in your test middleware node (&amp;lt;code&amp;gt;com.openexchange.documentconverter.client.remoteDocumentConverterUrl&amp;lt;/code&amp;gt;). Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle (as described below).&lt;br /&gt;
&lt;br /&gt;
== Final setup ==&lt;br /&gt;
&lt;br /&gt;
Assuming the test middleware node works as described in the previous section, do the same HAproxy configuration on all middleware nodes and configure the HAproxy endpoint &amp;lt;code&amp;gt;http://127.0.0.1:8008/documentconverterws&amp;lt;/code&amp;gt; in all middleware nodes' middleware configuration.&lt;br /&gt;
&lt;br /&gt;
The fully clustered setup should be working now.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
It is highly recommended to make sure you always end up on the same middleware node for testing, by whatever means is required in your infrastructure to do so. For this document we assume you can access them directly (internal testing). Otherwise you'd need to expose special entry points to your setup.&lt;br /&gt;
&lt;br /&gt;
If you can't ensure that, you need to configure all middleware nodes absolutely identical also during setup and testing, which is very cumbersome and error-prone.&lt;br /&gt;
&lt;br /&gt;
If you reconfigured something on the middleware node(s), restart the service there.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wipe out caches on the converter node(s) and restart the service there:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange-documentconverter-server stop&lt;br /&gt;
rm -rf /var/spool/open-xchange/documentconverter/readerengine.*/*&lt;br /&gt;
service open-xchange-documentconverter-server start&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Careful about your paths and when copy-pasting; I don't take responsibility of you remove something wrong.)&lt;br /&gt;
&lt;br /&gt;
If your testuser is logged in from a previous test, log out.&lt;br /&gt;
&lt;br /&gt;
Login your testuser.&lt;br /&gt;
&lt;br /&gt;
Access Drive. Upload test documents if not done before. Preferably some small trivial docs, also some large multi-page docs with embedded diagrams etc.&lt;br /&gt;
&lt;br /&gt;
Switch to &amp;quot;icons&amp;quot; or &amp;quot;tiles&amp;quot; view. You should get nice preview thumbnails for each document. (This is only a relevant test for the first time since the previews are stored in the database. TODO: find out how to wipe / re-test that.)&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;eye&amp;quot; icon to start the Document Viewer. You should be able to view documents with reasonable speed. Scrolling through the pages should be possible and fast.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;pop out&amp;quot; icon to the top right to use pop-out view. Verify all pages are rendered correctly in the full-page view and in the thumbnail previews.&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
In most of the times in our experiments if something was not working, it was a misconfiguration on network level. (Wrong hostnames, IPs, ports, missing firewall adjustments, etc).&lt;br /&gt;
&lt;br /&gt;
The documentconverter service&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23834</id>
		<title>User:Dominik.epple/DocumentConverterInstall</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23834"/>
		<updated>2018-02-16T09:28:41Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrough.&lt;br /&gt;
&lt;br /&gt;
The other relevant documentation is to be considered as a reference.&lt;br /&gt;
&lt;br /&gt;
This document describes the fully clustered setup. Simpler setups can be deduced as special case.&lt;br /&gt;
&lt;br /&gt;
This document has been created and verified on CentOS7 and OX App Suite 7.8.4.&lt;br /&gt;
&lt;br /&gt;
= Design description =&lt;br /&gt;
&lt;br /&gt;
We consider a clustered setup with multiple middleware nodes and multiple converter nodes.&lt;br /&gt;
&lt;br /&gt;
We consider a high available connection from the middleware nodes to the converter nodes realized using HAproxy instances running locally on the middleware nodes which do simple round-robin to the Apache instances of the Fronted nodes, which will do ''correct'' session stickyness aware routing to the converter nodes.&lt;br /&gt;
&lt;br /&gt;
We need the Apache instances to get correct ''session sticky'' routing behavior.&lt;br /&gt;
&lt;br /&gt;
We need the HAproxy instances to connect to the Apache instances in a high available fashion. If there are other means in the infrastructure offering that functionality, this is also okay. We present the HAproxy based setup to give an example of a fully working setup.&lt;br /&gt;
&lt;br /&gt;
= Software installation and configuration =&lt;br /&gt;
&lt;br /&gt;
== Middleware nodes ==&lt;br /&gt;
&lt;br /&gt;
Prerequisites: Drive is installed and working. We need Drive to upload test documents and verify their conversion. This also assumes (since we a discussing a clustered setup) a clustered filestore is available and working. If you are only going for a single node proof-of-concept setup, that is not relevant of course.&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-api open-xchange-documentconverter-client&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/opt/open-xchange/etc/permissions.properties:&lt;br /&gt;
# assume a global switch on for testing. further config cascade stuff etc is out of scope&lt;br /&gt;
# of this document.&lt;br /&gt;
com.openexchange.capability.document_preview=true&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://host[:port]/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frontend nodes ==&lt;br /&gt;
&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
== Converter nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-server open-xchange-documentconverter-api readerengine&lt;br /&gt;
&lt;br /&gt;
(Note: the official documentation also mentions &amp;quot;pdf2svg&amp;quot; which at least on CentOS7 does not exist, but rather a package named &amp;quot;readerengine-pdf2svg&amp;quot; is pulled as dependency. So for the moment let's assume we don't need to install that explicitly, but if you are following this guide on Debian you should double-check.)&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/etc/server.properties:&lt;br /&gt;
 # Pick a unique route, which will be configured consistently in apache&lt;br /&gt;
 com.openexchange.server.backendRoute=DC1&lt;br /&gt;
 # Clustered setups need to listen not only on localhost&lt;br /&gt;
 com.openexchange.connector.networkListenerHost=*&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/documentconverter/etc/documentconverter.properties &lt;br /&gt;
 # TODO figure out the recommended Cache setup for a clustered scenario&lt;br /&gt;
 com.openexchange.documentconverter.RemoteCacheUrls = ?&lt;br /&gt;
 # Default is 3. Adjust for your sizing.&lt;br /&gt;
 com.openexchange.documentconverter.jobProcessorCount=3&lt;br /&gt;
&lt;br /&gt;
Services configuration:&lt;br /&gt;
&lt;br /&gt;
 systemctl start open-xchange-documentconverter-server&lt;br /&gt;
 systemctl enable open-xchange-documentconverter-server&lt;br /&gt;
&lt;br /&gt;
= Configure the middleware to converter connectivity =&lt;br /&gt;
&lt;br /&gt;
So that was the trivial part. Now it gets interesting.&lt;br /&gt;
&lt;br /&gt;
== First test: direct connectivity ==&lt;br /&gt;
&lt;br /&gt;
Pick a middleware node. Configure direct connection to one converter service which is called &amp;lt;code&amp;gt;dc1&amp;lt;/code&amp;gt;. By default the service listens on port &amp;lt;code&amp;gt;8008&amp;lt;/code&amp;gt; and listens on the path &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://dc1:8008/documentconverterws/&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's how it should look like. HTTP status code 200 (not shown for clarity, but you can verify with curl -v, &amp;quot;WebService is running...&amp;quot;, &amp;quot;Error Code: 0&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If that is successful, go ahead and configure that URL in the middleware node&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://dc1:8008/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do a testing cycle as described below.&lt;br /&gt;
&lt;br /&gt;
If everything works, you confirmed that the middleware node and the converter node are configured correctly.&lt;br /&gt;
&lt;br /&gt;
Now ensure all your middleware nodes and all your converter nodes are configured likewise. Make sure the converter nodes get unique &amp;lt;code&amp;gt;com.openexchange.server.backendRoute&amp;lt;/code&amp;gt; values (see above).&lt;br /&gt;
&lt;br /&gt;
= Second test: use Apache for loadbalancing =&lt;br /&gt;
&lt;br /&gt;
Pick one frontend node to configure its Apache for loadbalancing for the converter nodes.&lt;br /&gt;
&lt;br /&gt;
There are sample configuration stanzas in our default configuration. They are just fine. Just make sure the &amp;lt;code&amp;gt;route&amp;lt;/code&amp;gt; parameters match the ones from the converter nodes.&lt;br /&gt;
&lt;br /&gt;
I want to emphasize to configure the &amp;lt;code&amp;gt;Allow&amp;lt;/code&amp;gt; line correctly. The &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt; endpoint must not be made available publicly!&lt;br /&gt;
&lt;br /&gt;
A sample Apache configuration looks like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;Proxy balancer://oxcluster_docs&amp;gt;&lt;br /&gt;
    Order Deny,Allow&lt;br /&gt;
    Deny from all&lt;br /&gt;
    # configure the allowed IPs such that only the middleware nodes are able to access&lt;br /&gt;
    # the /documentconverterws endpoint must not be made available publicly!&lt;br /&gt;
    Allow from 10.0.1&lt;br /&gt;
    BalancerMember http://dc1:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC1&lt;br /&gt;
    BalancerMember http://dc2:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC2&lt;br /&gt;
    # add further converter nodes, as many as you have&lt;br /&gt;
    ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&lt;br /&gt;
    SetEnv proxy-initial-not-pooled&lt;br /&gt;
    SetEnv proxy-sendchunked&lt;br /&gt;
&amp;lt;/Proxy&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProxyPass /documentconverterws balancer://oxcluster_docs/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With that configuration in place, test the connectivity from the middleware node to that endpoint, e.g. (assuming the frontend node is called &amp;lt;code&amp;gt;frontend1&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://frontend1/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The response looks exactly like before. The difference is just that we access the service now via Apache.&lt;br /&gt;
&lt;br /&gt;
Execute the test multiple times. It must answer fast every time. If some answers are slow (maybe only once or twice) that is an indication that some route configuration was incorrect and Apache disabled some converter targets.&lt;br /&gt;
&lt;br /&gt;
Make sure you are actually getting responses from the different converter nodes by whatever means suit you (e.g. tcpdump on the converter nodes, looking at Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt; to verify all nodes show up as &amp;lt;code&amp;gt;Ok&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;Elected&amp;lt;/code&amp;gt; number increases equally for all converter nodes, etc.)&lt;br /&gt;
&lt;br /&gt;
Configure that endpoint in your test middleware node. Restart the middleware service.&lt;br /&gt;
&lt;br /&gt;
Do a full test cycle as described below and in particular make sure that in pop-out view all preview images are rendered correctly. That is the testcase for correct session stickyness.&lt;br /&gt;
&lt;br /&gt;
If everything works correctly, make sure the Apache configuration is adjusted accordingly on all your Apache / Fronted nodes.&lt;br /&gt;
&lt;br /&gt;
Now we have high availability for the converter nodes, but the Apache service is still a SPOF.&lt;br /&gt;
&lt;br /&gt;
== Third test: adding local HAproxy instances ==&lt;br /&gt;
&lt;br /&gt;
We add local HAproxy instances to eliminate the Apache SPOF.&lt;br /&gt;
&lt;br /&gt;
Assuming HAproxy is already running locally for other services. If not, install it and do a basic configuration according to [HAproxy].&lt;br /&gt;
&lt;br /&gt;
Add a stanza like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;listen converter&lt;br /&gt;
    mode              http&lt;br /&gt;
    option            dontlognull&lt;br /&gt;
    option            redispatch&lt;br /&gt;
    no option         httpclose&lt;br /&gt;
    timeout connect   10s&lt;br /&gt;
    timeout client    2m&lt;br /&gt;
    timeout server    2m&lt;br /&gt;
    bind 127.0.0.1:8008&lt;br /&gt;
    balance roundrobin&lt;br /&gt;
    option httpchk GET /documentconverterws&lt;br /&gt;
    server frontend1 frontend1:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    server frontend2 frontend2:80 check port 80 inter 6000 rise 3 fall 1&lt;br /&gt;
    # add more frontend nodes if you have them&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Re-test that also this listener works correctly.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl  http://127.0.0.1:8008/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same as before, execute the test multiple times, and verify in the Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt;s that everything works as expected.&lt;br /&gt;
&lt;br /&gt;
Look at the HAproxy stats endpoint to verify all frontend nodes show as OK and get roughly the same number of sessions.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
If you reconfigured something on the middleware node(s), restart the service there.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wipe out caches on the converter node(s) and restart the service there:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange-documentconverter-server stop&lt;br /&gt;
rm -rf /var/spool/open-xchange/documentconverter/readerengine.*/*&lt;br /&gt;
service open-xchange-documentconverter-server start&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Careful about your paths and when copy-pasting; I don't take responsibility of you remove something wrong.)&lt;br /&gt;
&lt;br /&gt;
If your testuser is logged in from a previous test, log out.&lt;br /&gt;
&lt;br /&gt;
Login your testuser.&lt;br /&gt;
&lt;br /&gt;
Access Drive. Upload test documents if not done before. Preferably some small trivial docs, also some large multi-page docs with embedded diagrams etc.&lt;br /&gt;
&lt;br /&gt;
Switch to &amp;quot;icons&amp;quot; or &amp;quot;tiles&amp;quot; view. You should get nice preview thumbnails for each document. (This is only a relevant test for the first time since the previews are stored in the database. TODO: find out how to wipe / re-test that.)&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;eye&amp;quot; icon to start the Document Viewer. You should be able to view documents with reasonable speed. Scrolling through the pages should be possible and fast.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;pop out&amp;quot; icon to the top right to use pop-out view. Verify all pages are rendered correctly in the full-page view and in the thumbnail previews.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23833</id>
		<title>User:Dominik.epple/DocumentConverterInstall</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23833"/>
		<updated>2018-02-16T09:19:39Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrough.&lt;br /&gt;
&lt;br /&gt;
The other relevant documentation is to be considered as a reference.&lt;br /&gt;
&lt;br /&gt;
This document describes the fully clustered setup. Simpler setups can be deduced as special case.&lt;br /&gt;
&lt;br /&gt;
This document has been created and verified on CentOS7 and OX App Suite 7.8.4.&lt;br /&gt;
&lt;br /&gt;
= Design description =&lt;br /&gt;
&lt;br /&gt;
We consider a clustered setup with multiple middleware nodes and multiple converter nodes.&lt;br /&gt;
&lt;br /&gt;
We consider a high available connection from the middleware nodes to the converter nodes realized using HAproxy instances running locally on the middleware nodes which do simple round-robin to the Apache instances of the Fronted nodes, which will do ''correct'' session stickyness aware routing to the converter nodes.&lt;br /&gt;
&lt;br /&gt;
We need the Apache instances to get correct ''session sticky'' routing behavior.&lt;br /&gt;
&lt;br /&gt;
We need the HAproxy instances to connect to the Apache instances in a high available fashion. If there are other means in the infrastructure offering that functionality, this is also okay. We present the HAproxy based setup to give an example of a fully working setup.&lt;br /&gt;
&lt;br /&gt;
= Software installation and configuration =&lt;br /&gt;
&lt;br /&gt;
== Middleware nodes ==&lt;br /&gt;
&lt;br /&gt;
Prerequisites: Drive is installed and working. We need Drive to upload test documents and verify their conversion. This also assumes (since we a discussing a clustered setup) a clustered filestore is available and working. If you are only going for a single node proof-of-concept setup, that is not relevant of course.&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-api open-xchange-documentconverter-client&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/opt/open-xchange/etc/permissions.properties:&lt;br /&gt;
# assume a global switch on for testing. further config cascade stuff etc is out of scope&lt;br /&gt;
# of this document.&lt;br /&gt;
com.openexchange.capability.document_preview=true&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://host[:port]/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frontend nodes ==&lt;br /&gt;
&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
== Converter nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-server open-xchange-documentconverter-api readerengine&lt;br /&gt;
&lt;br /&gt;
(Note: the official documentation also mentions &amp;quot;pdf2svg&amp;quot; which at least on CentOS7 does not exist, but rather a package named &amp;quot;readerengine-pdf2svg&amp;quot; is pulled as dependency. So for the moment let's assume we don't need to install that explicitly, but if you are following this guide on Debian you should double-check.)&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/etc/server.properties:&lt;br /&gt;
 # Pick a unique route, which will be configured consistently in apache&lt;br /&gt;
 com.openexchange.server.backendRoute=DC1&lt;br /&gt;
 # Clustered setups need to listen not only on localhost&lt;br /&gt;
 com.openexchange.connector.networkListenerHost=*&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/documentconverter/etc/documentconverter.properties &lt;br /&gt;
 # TODO figure out the recommended Cache setup for a clustered scenario&lt;br /&gt;
 com.openexchange.documentconverter.RemoteCacheUrls = ?&lt;br /&gt;
 # Default is 3. Adjust for your sizing.&lt;br /&gt;
 com.openexchange.documentconverter.jobProcessorCount=3&lt;br /&gt;
&lt;br /&gt;
Services configuration:&lt;br /&gt;
&lt;br /&gt;
 systemctl start open-xchange-documentconverter-server&lt;br /&gt;
 systemctl enable open-xchange-documentconverter-server&lt;br /&gt;
&lt;br /&gt;
= Configure the middleware to converter connectivity =&lt;br /&gt;
&lt;br /&gt;
So that was the trivial part. Now it gets interesting.&lt;br /&gt;
&lt;br /&gt;
== First test: direct connectivity ==&lt;br /&gt;
&lt;br /&gt;
Pick a middleware node. Configure direct connection to one converter service which is called &amp;lt;code&amp;gt;dc1&amp;lt;/code&amp;gt;. By default the service listens on port &amp;lt;code&amp;gt;8008&amp;lt;/code&amp;gt; and listens on the path &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://dc1:8008/documentconverterws/&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's how it should look like. HTTP status code 200 (not shown for clarity, but you can verify with curl -v, &amp;quot;WebService is running...&amp;quot;, &amp;quot;Error Code: 0&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If that is successful, go ahead and configure that URL in the middleware node&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://dc1:8008/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do a testing cycle as described below.&lt;br /&gt;
&lt;br /&gt;
If everything works, you confirmed that the middleware node and the converter node are configured correctly.&lt;br /&gt;
&lt;br /&gt;
Now ensure all your middleware nodes and all your converter nodes are configured likewise. Make sure the converter nodes get unique &amp;lt;code&amp;gt;com.openexchange.server.backendRoute&amp;lt;/code&amp;gt; values (see above).&lt;br /&gt;
&lt;br /&gt;
= Second test: use Apache for loadbalancing =&lt;br /&gt;
&lt;br /&gt;
Pick one frontend node to configure its Apache for loadbalancing for the converter nodes.&lt;br /&gt;
&lt;br /&gt;
There are sample configuration stanzas in our default configuration. They are just fine. Just make sure the &amp;lt;code&amp;gt;route&amp;lt;/code&amp;gt; parameters match the ones from the converter nodes.&lt;br /&gt;
&lt;br /&gt;
I want to emphasize to configure the &amp;lt;code&amp;gt;Allow&amp;lt;/code&amp;gt; line correctly. The &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt; endpoint must not be made available publicly!&lt;br /&gt;
&lt;br /&gt;
A sample Apache configuration looks like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;Proxy balancer://oxcluster_docs&amp;gt;&lt;br /&gt;
    Order Deny,Allow&lt;br /&gt;
    Deny from all&lt;br /&gt;
    # configure the allowed IPs such that only the middleware nodes are able to access&lt;br /&gt;
    # the /documentconverterws endpoint must not be made available publicly!&lt;br /&gt;
    Allow from 10.0.1&lt;br /&gt;
    BalancerMember http://dc1:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC1&lt;br /&gt;
    BalancerMember http://dc2:8008 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=DC2&lt;br /&gt;
    # add further converter nodes, as many as you have&lt;br /&gt;
    ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&lt;br /&gt;
    SetEnv proxy-initial-not-pooled&lt;br /&gt;
    SetEnv proxy-sendchunked&lt;br /&gt;
&amp;lt;/Proxy&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ProxyPass /documentconverterws balancer://oxcluster_docs/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With that configuration in place, test the connectivity from the middleware node to that endpoint, e.g. (assuming the frontend node is called &amp;lt;code&amp;gt;frontend1&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://frontend1/documentconverterws&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The response looks exactly like before. The difference is just that we access the service now via Apache.&lt;br /&gt;
&lt;br /&gt;
Make sure you are actually getting responses from the different converter nodes by whatever means suit you (e.g. tcpdump on the converter nodes, looking at Apache's &amp;lt;code&amp;gt;balancer-manager&amp;lt;/code&amp;gt; to verify the &amp;lt;code&amp;gt;elected&amp;lt;/code&amp;gt; number increases equally for all converter nodes, etc.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
If you reconfigured something on the middleware node(s), restart the service there.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wipe out caches on the converter node(s) and restart the service there:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange-documentconverter-server stop&lt;br /&gt;
rm -rf /var/spool/open-xchange/documentconverter/readerengine.*/*&lt;br /&gt;
service open-xchange-documentconverter-server start&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Careful about your paths and when copy-pasting; I don't take responsibility of you remove something wrong.)&lt;br /&gt;
&lt;br /&gt;
If your testuser is logged in from a previous test, log out.&lt;br /&gt;
&lt;br /&gt;
Login your testuser.&lt;br /&gt;
&lt;br /&gt;
Access Drive. Upload test documents if not done before. Preferably some small trivial docs, also some large multi-page docs with embedded diagrams etc.&lt;br /&gt;
&lt;br /&gt;
Switch to &amp;quot;icons&amp;quot; or &amp;quot;tiles&amp;quot; view. You should get nice preview thumbnails for each document. (This is only a relevant test for the first time since the previews are stored in the database. TODO: find out how to wipe / re-test that.)&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;eye&amp;quot; icon to start the Document Viewer. You should be able to view documents with reasonable speed. Scrolling through the pages should be possible and fast.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;pop out&amp;quot; icon to the top right to use pop-out view. Verify all pages are rendered correctly in the full-page view and in the thumbnail previews.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23832</id>
		<title>User:Dominik.epple/DocumentConverterInstall</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23832"/>
		<updated>2018-02-16T09:05:08Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrough.&lt;br /&gt;
&lt;br /&gt;
The other relevant documentation is to be considered as a reference.&lt;br /&gt;
&lt;br /&gt;
This document describes the fully clustered setup. Simpler setups can be deduced as special case.&lt;br /&gt;
&lt;br /&gt;
This document has been created and verified on CentOS7 and OX App Suite 7.8.4.&lt;br /&gt;
&lt;br /&gt;
= Design description =&lt;br /&gt;
&lt;br /&gt;
We consider a clustered setup with multiple middleware nodes and multiple converter nodes.&lt;br /&gt;
&lt;br /&gt;
= Software installation and configuration =&lt;br /&gt;
&lt;br /&gt;
== Middleware nodes ==&lt;br /&gt;
&lt;br /&gt;
Prerequisites: Drive is installed and working. We need Drive to upload test documents and verify their conversion. This also assumes (since we a discussing a clustered setup) a clustered filestore is available and working. If you are only going for a single node proof-of-concept setup, that is not relevant of course.&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-api open-xchange-documentconverter-client&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/opt/open-xchange/etc/permissions.properties:&lt;br /&gt;
# assume a global switch on for testing. further config cascade stuff etc is out of scope&lt;br /&gt;
# of this document.&lt;br /&gt;
com.openexchange.capability.document_preview=true&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://host[:port]/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frontend nodes ==&lt;br /&gt;
&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
== Converter nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-server open-xchange-documentconverter-api readerengine&lt;br /&gt;
&lt;br /&gt;
(Note: the official documentation also mentions &amp;quot;pdf2svg&amp;quot; which at least on CentOS7 does not exist, but rather a package named &amp;quot;readerengine-pdf2svg&amp;quot; is pulled as dependency. So for the moment let's assume we don't need to install that explicitly, but if you are following this guide on Debian you should double-check.)&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/etc/server.properties:&lt;br /&gt;
 # Pick a unique route, which will be configured consistently in apache&lt;br /&gt;
 com.openexchange.server.backendRoute=DC1&lt;br /&gt;
 # Clustered setups need to listen not only on localhost&lt;br /&gt;
 com.openexchange.connector.networkListenerHost=*&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/documentconverter/etc/documentconverter.properties &lt;br /&gt;
 # TODO figure out the recommended Cache setup for a clustered scenario&lt;br /&gt;
 com.openexchange.documentconverter.RemoteCacheUrls = ?&lt;br /&gt;
 # Default is 3. Adjust for your sizing.&lt;br /&gt;
 com.openexchange.documentconverter.jobProcessorCount=3&lt;br /&gt;
&lt;br /&gt;
Services configuration:&lt;br /&gt;
&lt;br /&gt;
 systemctl start open-xchange-documentconverter-server&lt;br /&gt;
 systemctl enable open-xchange-documentconverter-server&lt;br /&gt;
&lt;br /&gt;
= Configure the middleware to converter connectivity =&lt;br /&gt;
&lt;br /&gt;
So that was the trivial part. Now it gets interesting.&lt;br /&gt;
&lt;br /&gt;
== First test: direct connectivity ==&lt;br /&gt;
&lt;br /&gt;
Pick a middleware node. Configure direct connection to one converter service which is called &amp;lt;code&amp;gt;dc1&amp;lt;/code&amp;gt;. By default the service listens on port &amp;lt;code&amp;gt;8008&amp;lt;/code&amp;gt; and listens on the path &amp;lt;code&amp;gt;/documentconverterws&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://dc1:8008/documentconverterws/&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's how it should look like. HTTP status code 200 (not shown for clarity, but you can verify with curl -v, &amp;quot;WebService is running...&amp;quot;, &amp;quot;Error Code: 0&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If that is successful, go ahead and configure that URL in the middleware node&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://dc1:8008/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do a testing cycle as described below.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
If you reconfigured something on the middleware node(s), restart the service there.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange restart&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wipe out caches on the converter node(s) and restart the service there:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;service open-xchange-documentconverter-server stop&lt;br /&gt;
rm -rf /var/spool/open-xchange/documentconverter/readerengine.*/*&lt;br /&gt;
service open-xchange-documentconverter-server start&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Careful about your paths and when copy-pasting; I don't take responsibility of you remove something wrong.)&lt;br /&gt;
&lt;br /&gt;
If your testuser is logged in from a previous test, log out.&lt;br /&gt;
&lt;br /&gt;
Login your testuser.&lt;br /&gt;
&lt;br /&gt;
Access Drive. Upload test documents if not done before. Preferably some small trivial docs, also some large multi-page docs with embedded diagrams etc.&lt;br /&gt;
&lt;br /&gt;
Switch to &amp;quot;icons&amp;quot; or &amp;quot;tiles&amp;quot; view. You should get nice preview thumbnails for each document. (This is only a relevant test for the first time since the previews are stored in the database. TODO: find out how to wipe / re-test that.)&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;eye&amp;quot; icon to start the Document Viewer. You should be able to view documents with reasonable speed. Scrolling through the pages should be possible and fast.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;pop out&amp;quot; icon to the top right to use pop-out view. Verify all pages are rendered correctly in the full-page view and in the thumbnail previews.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23831</id>
		<title>User:Dominik.epple/DocumentConverterInstall</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple/DocumentConverterInstall&amp;diff=23831"/>
		<updated>2018-02-16T08:50:48Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: Created page with &amp;quot;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;  __TOC__  = Introduction =  This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrou...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;DocumentConverter Quickinstall Guide / Cheatsheet&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document aims to be a condensed &amp;quot;HOWTO&amp;quot; like installation walkthrough.&lt;br /&gt;
&lt;br /&gt;
The other relevant documentation is to be considered as a reference.&lt;br /&gt;
&lt;br /&gt;
This document describes the fully clustered setup. Simpler setups can be deduced as special case.&lt;br /&gt;
&lt;br /&gt;
This document has been created and verified on CentOS7 and OX App Suite 7.8.4.&lt;br /&gt;
&lt;br /&gt;
= Design description =&lt;br /&gt;
&lt;br /&gt;
We consider a clustered setup with multiple middleware nodes and multiple converter nodes.&lt;br /&gt;
&lt;br /&gt;
= Software installation and configuration =&lt;br /&gt;
&lt;br /&gt;
== Middleware nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-api open-xchange-documentconverter-client&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;/opt/open-xchange/etc/permissions.properties:&lt;br /&gt;
# assume a global switch on for testing. further config cascade stuff etc is out of scope&lt;br /&gt;
# of this document.&lt;br /&gt;
com.openexchange.capability.document_preview=true&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;documentconverter-client.properties:&lt;br /&gt;
# this needs to be adjusted. will be discussed below.&lt;br /&gt;
com.openexchange.documentconverter.client.remoteDocumentConverterUrl=http://host[:port]/documentconverterws&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Frontend nodes ==&lt;br /&gt;
&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
== Converter nodes ==&lt;br /&gt;
&lt;br /&gt;
Packages to be installed:&lt;br /&gt;
&lt;br /&gt;
 open-xchange-documentconverter-server open-xchange-documentconverter-api readerengine&lt;br /&gt;
&lt;br /&gt;
(Note: the official documentation also mentions &amp;quot;pdf2svg&amp;quot; which at least on CentOS7 does not exist, but rather a package named &amp;quot;readerengine-pdf2svg&amp;quot; is pulled as dependency. So for the moment let's assume we don't need to install that explicitly, but if you are following this guide on Debian you should double-check.)&lt;br /&gt;
&lt;br /&gt;
Configuration:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/etc/server.properties:&lt;br /&gt;
 # Pick a unique route, which will be configured consistently in apache&lt;br /&gt;
 com.openexchange.server.backendRoute=DC1&lt;br /&gt;
 # Clustered setups need to listen not only on localhost&lt;br /&gt;
 com.openexchange.connector.networkListenerHost=*&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/documentconverter/etc/documentconverter.properties &lt;br /&gt;
 # TODO figure out the recommended Cache setup for a clustered scenario&lt;br /&gt;
 com.openexchange.documentconverter.RemoteCacheUrls = ?&lt;br /&gt;
 # Default is 3. Adjust for your sizing.&lt;br /&gt;
 com.openexchange.documentconverter.jobProcessorCount=3&lt;br /&gt;
&lt;br /&gt;
Services configuration:&lt;br /&gt;
&lt;br /&gt;
 systemctl start open-xchange-documentconverter-server&lt;br /&gt;
 systemctl enable open-xchange-documentconverter-server&lt;br /&gt;
&lt;br /&gt;
= Configure the middleware to converter connectivity =&lt;br /&gt;
&lt;br /&gt;
So that was the trivial part. Now it gets interesting.&lt;br /&gt;
&lt;br /&gt;
== First test: direct connectivity ==&lt;br /&gt;
&lt;br /&gt;
Pick a middleware node. Configure direct connection to one converter service:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;# curl http://ccdc1:8008/documentconverterws/&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;&amp;lt;title&amp;gt;Open-Xchange DC&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;h1 align=&amp;quot;center&amp;quot;&amp;gt;OX Software GmbH DC&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;WebService is running...&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Error Code: 0&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;API: v5&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That's how it should look like. HTTP status code 200 (not shown for clarity, but you can verify with curl -v, &amp;quot;WebService is running...&amp;quot;, &amp;quot;Error Code: 0&amp;quot;.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=23804</id>
		<title>Template:OXLoadBalancingClustering Database</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Template:OXLoadBalancingClustering_Database&amp;diff=23804"/>
		<updated>2018-01-26T16:47:17Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
You can choose between Galera or Master/Slave replication. We like to recommend to use Galera for higher redudancy, easier operations, und synchronous semantics (so you can run OX without our &amp;quot;replication monitor&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Galera database setup ==&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to Galera cluster, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Please follow the upstream docs for your preferred flavor to get the software installed on your system.&lt;br /&gt;
&lt;br /&gt;
* Percona XtraDB Cluster (5.6, 5.7): https://www.percona.com/doc/percona-xtradb-cluster/LATEST/install/index.html&lt;br /&gt;
* MariaDB Galera Cluster (10.0, 10.1): https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/ (Note: with 10.0, socat is required, but not a package dependency, so you need to explicitly install also socat)&lt;br /&gt;
&lt;br /&gt;
Make sure to doublecheck the service is not running (or stop it) after installation as we need to perform some reconfigurations.&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Galera-specific MySQL configuration advise is included in our main [[My.cnf|MySQL configuration article]]. Please consult that page for configuration information.&lt;br /&gt;
&lt;br /&gt;
That page suggests a setup were we add three custom config files to &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/&amp;lt;/pre&amp;gt;: &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; for general tuning/sizing, &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; for clusterwide galera configuration, and &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; for host-specific settings.&lt;br /&gt;
&lt;br /&gt;
Adjust the general settings and tunings in &amp;lt;code&amp;gt;ox.cnf&amp;lt;/code&amp;gt; according to your sizing etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;wsrep.cnf&amp;lt;/code&amp;gt; to reflect local paths, cluster member addresses, etc.&lt;br /&gt;
&lt;br /&gt;
Adjust &amp;lt;code&amp;gt;host.cnf&amp;lt;/code&amp;gt; to give node-local IPs, etc.&lt;br /&gt;
&lt;br /&gt;
Version-specific hints:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6: unknown variable 'pxc_strict_mode=ENFORCING' ... unset that one&lt;br /&gt;
 # mariadb 10.1: add wsrep_on=ON&lt;br /&gt;
 # mariadb 10.0 and 10.1: set wsrep_node_incoming_address=192.168.1.22:3306 in host.cnf, otherwise the status wsrep_incoming_addresses might not be shown correctly(?!)&lt;br /&gt;
&lt;br /&gt;
Some settings we recommend to change require that the database gets re-initialized. We assume you don't have data there (since we are covering a fresh install) or you have taken a backup for later restore as explained above in the Preparations section.&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
 &lt;br /&gt;
 # mariadb 10.0 and 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 # percona 5.6&lt;br /&gt;
 mysqld --user=mysql&lt;br /&gt;
 # percona 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
=== Cluster startup ===&lt;br /&gt;
&lt;br /&gt;
Typically on startup a Galera node tries to join a cluster, and if it fails, it will exit. Thus, when no cluster nodes are running, the first cluster node to be started needs to be told to not try to join a cluster, but rather bootstrap a new cluster. The exact arguments vary from version to version and from flavor to flavor.&lt;br /&gt;
&lt;br /&gt;
==== First node ====&lt;br /&gt;
&lt;br /&gt;
So we initialize the cluster bootstrap on the first node:&lt;br /&gt;
&lt;br /&gt;
 # percona 5.6, 5.7&lt;br /&gt;
 service mysql bootstrap-pxc&lt;br /&gt;
 # mariadb 10.0&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
 # mariadb 10.1: service mysql bootstrap seems to be broken, does not pass the necessary options to mysqld&lt;br /&gt;
 galera_new_cluster&lt;br /&gt;
&lt;br /&gt;
Run &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt; for a &amp;quot;secure by default&amp;quot; installation:&lt;br /&gt;
&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
The further steps in this guide omit &amp;lt;code&amp;gt;-u -p&amp;lt;/code&amp;gt; arguments to the MySQL client. Rather than passing them on the command line [https://dev.mysql.com/doc/refman/5.7/en/password-security-user.html] it is recommended to place the credentials in a file like &amp;lt;code&amp;gt;/root/.my.cnf&amp;lt;/code&amp;gt; like&lt;br /&gt;
&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=wip9Phae3Beijeed&lt;br /&gt;
&lt;br /&gt;
We need a Galera replication user:&lt;br /&gt;
&lt;br /&gt;
 CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'OpIdjijwef0';&lt;br /&gt;
 -- percona 5.6, mariadb 10.0&lt;br /&gt;
 GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 -- percona 5.7, mariadb 10.1&lt;br /&gt;
 GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';&lt;br /&gt;
 FLUSH PRIVILEGES;&lt;br /&gt;
&lt;br /&gt;
(Debian specific note: MariaDB provided startup scripts use the distro's mechanism of verifying startup/shutdown using a system user, so we create that as well:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.0, 10.1&lt;br /&gt;
 GRANT ALL PRIVILEGES ON *.* TO &amp;quot;debian-sys-maint&amp;quot;@&amp;quot;localhost&amp;quot; IDENTIFIED BY &amp;quot;adBexthTsI5TaEps&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If you do this, yo need to synchronize the &amp;lt;code&amp;gt;/etc/mysql/debian.cnf&amp;lt;/code&amp;gt; file from the first node to the other nodes as well.)&lt;br /&gt;
&lt;br /&gt;
==== Other nodes ====&lt;br /&gt;
&lt;br /&gt;
On the other nodes, we only need to restart the service now, to trigger a full state transfer from the first node to the other nodes.&lt;br /&gt;
&lt;br /&gt;
We recommend to do this serially to let one state transfer complete before the second state transfer.&lt;br /&gt;
&lt;br /&gt;
==== First node (continued) ====&lt;br /&gt;
&lt;br /&gt;
Only applicable if you used &amp;lt;code&amp;gt;galera_new_cluster&amp;lt;/code&amp;gt; before rather than the service script: In order to get the systemctl status consistent, restart the service on the first node:&lt;br /&gt;
&lt;br /&gt;
 # mariadb 10.1: restart the service so that the systemctl status is consistent&lt;br /&gt;
 mysqladmin shutdown&lt;br /&gt;
 service mysql bootstrap&lt;br /&gt;
&lt;br /&gt;
=== Verify the replication ===&lt;br /&gt;
&lt;br /&gt;
The key tool to verify replication status is&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; show status like &amp;quot;%wsrep%&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
This will give a lot of output. You want to verify in particular&lt;br /&gt;
&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | Variable_name                | Value                                |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
 | wsrep_cluster_size           | 3                                    |&lt;br /&gt;
 | wsrep_cluster_status         | Primary                              |&lt;br /&gt;
 | wsrep_local_state            | 4                                    |&lt;br /&gt;
 | wsrep_local_state_comment    | Synced                               |&lt;br /&gt;
 | wsrep_ready                  | ON                                   |&lt;br /&gt;
 +------------------------------+--------------------------------------+&lt;br /&gt;
&lt;br /&gt;
You can also explicitly verify replication by creating / inserting DBs, tables, rows on one node and select on other nodes.&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
&lt;br /&gt;
The logs are helpful. Always.&lt;br /&gt;
&lt;br /&gt;
Common mistakes are listed below.&lt;br /&gt;
&lt;br /&gt;
If the Galera module does not get loaded at all:&lt;br /&gt;
* Configuration settings in ''my.cnf'' which are incompatible to Galera&lt;br /&gt;
* Wrong path of the shared object providing the Galera plugin in wsrep.cnf (wsrep_provider)&lt;br /&gt;
&lt;br /&gt;
If the first node starts, but the second / third nodes can not be added to the cluster:&lt;br /&gt;
* User for the replication not created correctly on the first Galera node&lt;br /&gt;
* SST fails due to missing / wrong version prerequisite packages (not everything is hardcoded in package dependencies -- make sure you got percona-xtrabackup installed in the correct version, and also socat). If SST fails, do not only look into mysqls primary error logs, but also into logfiles from the SST tool in /var/lib/mysql on the donor node.&lt;br /&gt;
&lt;br /&gt;
=== Notes about configuring OX for use with Galera ===&lt;br /&gt;
&lt;br /&gt;
==== Write requests ====&lt;br /&gt;
&lt;br /&gt;
Open-Xchange supports Galera as database backend only in the configuration where all writes are directed to one Galera node. For availability, it makes sense to not configure one Galera node's IP address directly, but rather employ some HA solution which offers active-passive functionality. Options therefore are discussed below.&lt;br /&gt;
&lt;br /&gt;
==== Read requests ====&lt;br /&gt;
&lt;br /&gt;
Read requests can be directed to any node in the Galera cluster. Our standard approach is to recommend to use a loadbalancer to implement round-robin over all nodes in a Galera cluster for the read requests. But you can also chose to use a dedicated read node (the same node, or a different node, than the write node). Each of the approaches has its own advantages.&lt;br /&gt;
&lt;br /&gt;
* Load balancer based setup: Read requests get distributed round-robin between the Galera nodes. Theoretically by distributing the load of the read requests, you benefit from lower latencies and more throughput. But this has never been benchmarked yet. For a discussion of available loadbalances, see next section. OX-wise, in this configuration, you have two alternatives: &lt;br /&gt;
** The Galera option wsrep_causal_reads=1 option enables you to configure OX with its replication monitor disabled (com.openexchange.database.replicationMonitor=false in configdb.properties). This is the setup which seems to perform best according to our experience as turning off the replication monitor reduces the commits on the DB and thus the write operations per second on the underlying storage significantly, which outweights the drawback from having higher commit latency due to fully synchronous mode.&lt;br /&gt;
** Alternatively, you can run Galera with wsrep_causal_reads=0 when switching on OX builtin replication monitor. This is also a valid setup.&lt;br /&gt;
* Use a designated floating IP for the read requests: This eliminates the need of a load balancer. With this option you will not gain any performance, but the quantitative benefit is unclear anyhow.&lt;br /&gt;
* Use the floating IP for the writes also for the reads: In this scenario, you direct all database queries only to one Galera node, and the other two nodes are only getting queries in case of a failure of that node. In this case, you can even use wsrep_causal_reads=0 while still having OX builtin replication monitor switched off. However we do not expect this option to be superior to the round-robin loadbalancer approach.&lt;br /&gt;
&lt;br /&gt;
=== Loadbalancer options ===&lt;br /&gt;
&lt;br /&gt;
While the JDBC driver has some round-robin load balancing capabilities built-in, we don't recommend it for production use since it lacks possibilities to check the Galera nodes health states.&lt;br /&gt;
&lt;br /&gt;
Loadbalancers used for OX -&amp;gt; Galera loadbalancing should be able to implement active-passive instances for the write requests, and active-active (round-robin) instances for the read requests. (If they cannot implement active-passive, you can still take a floating IP therefore.) Furthermore it is required to configure node health checks not only on the TCP level (by a simple connect), but to query the Galera health status periodically, evaluating Galera WSREP status variables. Otherwise split-brain scenarios or other bad states cannot be detected. For an example of such an health check, see our [[Clustercheck]] page.&lt;br /&gt;
&lt;br /&gt;
Some customers use loadbalancing appliances. It is important to check that if the (virtual) infrastructure offers &amp;quot;loadbalancer&amp;quot; instances that they satisfy the given requirements. Often this is not the case. In particular, a simple &amp;quot;DNS round robin&amp;quot; approach is not viable.&lt;br /&gt;
&lt;br /&gt;
==== LVS/ipvsadm/keepalived ====&lt;br /&gt;
&lt;br /&gt;
If you want to create your own loadbalancers based on Linux, we usually recommend LVS (Linux Virtual Servers) controlled by Keepalived. LVS is a set of kernel modules implementing a L4 loadbalancer which performs quite well. Keepalived is a userspace daemon to control LVS rules, using health checks to reconfigure LVS rules if required. Keepalived / LVS requires one (or, for availability, two) dedicated linux nodes to run on. This can be a disadvantage for some installations, but usually, it pays off. We provide some configuration information on Keepalived [[Keepalived|here]].&lt;br /&gt;
&lt;br /&gt;
==== MariaDB Maxscale ====&lt;br /&gt;
&lt;br /&gt;
Since Maxscale has become GA in 2015, it seems to have undergone significant stability, performance and functional improvements. We are currently experimenting with Maxscale and share our installation / configuration knowledge [[Maxscale|here]]. It looks quite promising and might become ''the standard replacement'' for HAproxy, while we still presume Keepalived offers superior robustness and performance, coming with the cost of the requirement for one (or more) dedicated loadbalancer nodes.&lt;br /&gt;
&lt;br /&gt;
==== HAproxy ====&lt;br /&gt;
&lt;br /&gt;
In case where the Keepalived based approach is not feasible due to its requirements on the infrastructure, it is also possible to use a HAproxy based solution where HAproxy processes run on each of the OX nodes, configured for one round-robin and one active/passive instance. OX is then connecting to the local HAproxy instances. It is vital to configure HAproxy timeouts different from the defaults, otherwise HAproxy will kill active DB connections, causing errors. Be aware that in large installations the number of (distributed) HAproxy instances can get quite large. Some configuration hints for HAproxy are available [[HAproxy|here]].&lt;br /&gt;
&lt;br /&gt;
== Master/Slave database setup ==&lt;br /&gt;
&lt;br /&gt;
While we also support also &amp;quot;legacy&amp;quot; (pre-GTID) Master/Slave replication, we recommend to use GTID based replication, for easier setup and failure recovery. Support for GTID based replication has been added with OX 7.8.0.&lt;br /&gt;
&lt;br /&gt;
GTID has been available since MySQL 5.6, so no 5.5 installation instructions below, sorry. We try to be generic in this documentation (thus, applicable to Oracle Community Edition and MariaDB) and point out differences where needed. Note: Instructions below include information about Oracle Community MySQL 5.7 which is not yet formally supported.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
Our configuration process includes wiping and reinitializing the datadir. This is usually not a problem in a fresh installation. If you want to upgrade an existing database to GTID master-slave, please be prepared to wipe the datadir, i.e. take a &amp;lt;code&amp;gt;mysqldump&amp;lt;/code&amp;gt; for later restoration into the properly configured master.&lt;br /&gt;
&lt;br /&gt;
Depeding on the flavor of the current database, this can be something like&lt;br /&gt;
&lt;br /&gt;
 # mariadb or oracle mysql without GTIDs&lt;br /&gt;
 mysqldump --databases configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
 &lt;br /&gt;
 # mysql 5.6 with GTIDs... we dont want GTIDs here&lt;br /&gt;
 mysqldump --databases --set-gtid-purged=OFF configdb oxdb_{5..14} &amp;gt; backup.sql&lt;br /&gt;
&lt;br /&gt;
Be sure to verify the list of databases.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
&lt;br /&gt;
Software installation is identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions for installing from The vendors.&lt;br /&gt;
&lt;br /&gt;
* Oracle Community Edition: https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/&lt;br /&gt;
* MariaDB (10.0, 10.1): https://downloads.mariadb.org/mariadb/repositories/&lt;br /&gt;
&lt;br /&gt;
Stop the service (if it is running):&lt;br /&gt;
&lt;br /&gt;
 service mysql stop&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Configuration as per configuration files is also identical for master and slave.&lt;br /&gt;
&lt;br /&gt;
Consult [[My.cnf]] for general recommendations how to configure databases for usage with OX.&lt;br /&gt;
&lt;br /&gt;
For GTID based replication, make sure you add some configurables to a new &amp;lt;code&amp;gt;/etc/mysql/ox.conf.d/gtid.cnf&amp;lt;/code&amp;gt; file (assuming you are following our proposed schema of adding a &amp;lt;code&amp;gt;!includedir /etc/mysql/ox.conf.d/&amp;lt;/code&amp;gt;&amp;quot; directive to &amp;lt;code&amp;gt;/etc/mysql/my.cnf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 # GTID&lt;br /&gt;
 log-bin=mysql-bin&lt;br /&gt;
 server-id=...&lt;br /&gt;
 log_slave_updates = ON&lt;br /&gt;
&lt;br /&gt;
Oracle Community Edition: we need to add also&lt;br /&gt;
&lt;br /&gt;
 enforce_gtid_consistency = ON&lt;br /&gt;
 gtid_mode = ON&lt;br /&gt;
&lt;br /&gt;
(GTID mode is on by default on MariaDB.)&lt;br /&gt;
&lt;br /&gt;
Use unique a &amp;lt;code&amp;gt;server-id&amp;lt;/code&amp;gt; for each server; like &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; for the master, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; for slave. For more complicated setups (like multiple slaves), adjust accordingly.&lt;br /&gt;
&lt;br /&gt;
Since applying our configuration / sizing requires reinitialization of the MySQL datadir, we wipe/recreate it. Caution: this assumes we are running an empty database. If there is data in the database you want to keep, use mysqldump. See Preparation section above.&lt;br /&gt;
&lt;br /&gt;
So, to initialize the datadir:&lt;br /&gt;
&lt;br /&gt;
 cd /var/lib/&lt;br /&gt;
 mv mysql mysql.old.datadir&lt;br /&gt;
 mkdir mysql&lt;br /&gt;
 chown mysql.mysql mysql&lt;br /&gt;
&lt;br /&gt;
(When coming from an existing installation, be sure to wipe also old binlogs. They can confuse the server on startup. Their location varies by configuration.)&lt;br /&gt;
&lt;br /&gt;
The step to initialize the datadir is different for the different DBs:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB 10.0, 10.1&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.6&lt;br /&gt;
 mysql_install_db -u mysql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle 5.7&lt;br /&gt;
 mysqld --initialize-insecure --user=mysql&lt;br /&gt;
&lt;br /&gt;
(Don't be worried about the &amp;lt;code&amp;gt;insecure&amp;lt;/code&amp;gt;, it just means we set the db root pw in the next steps.)&lt;br /&gt;
&lt;br /&gt;
Then:&lt;br /&gt;
&lt;br /&gt;
 service mysql restart&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
&lt;br /&gt;
We want to emphasize the last step to run &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Steps up to here apply to both the designated master and slave. The next steps will apply to the master.&lt;br /&gt;
&lt;br /&gt;
=== Replication Setup ===&lt;br /&gt;
&lt;br /&gt;
==== Master Setup ====&lt;br /&gt;
&lt;br /&gt;
Create a replication user on the master (but, as always, pick your own password, and use the same password in the slave setup below):&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;CREATE USER 'repl'@'gtid-slave.localdomain' IDENTIFIED BY 'IvIjyoffod2'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'gtid-slave.localdomain';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Now would also be the time to restore a previously created mysqldump, or add other users you need for adminstration, monitoring etc (like &amp;lt;code&amp;gt;debian-sys-maint@localhost&amp;lt;/code&amp;gt;, for example). Adding the OX users is explained below (&amp;quot;Creating Open-Xchange user&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
 # If you took a dump for restore before&lt;br /&gt;
 mysql &amp;lt; backup.sql&lt;br /&gt;
&lt;br /&gt;
To prepare for the initial sync of the slave, set the master read-only:&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = ON;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Create a dump to initialize the slave:&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --master-data --gtid &amp;gt; master.sql&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysqldump --all-databases --triggers --routines --events --set-gtid-purged=ON &amp;gt; master.sql&lt;br /&gt;
&lt;br /&gt;
Transfer to the slave:&lt;br /&gt;
&lt;br /&gt;
 scp master.sql gtid-slave:&lt;br /&gt;
&lt;br /&gt;
==== Slave Setup ====&lt;br /&gt;
&lt;br /&gt;
Configure the replication master settings. Note we don't need complicated binlog position settings etc with GTID.&lt;br /&gt;
&lt;br /&gt;
Yet again DB-specific (use the repl user password from above):&lt;br /&gt;
&lt;br /&gt;
 # MariaDB&lt;br /&gt;
 mysql -e 'CHANGE MASTER TO MASTER_HOST=&amp;quot;gtid-master.localdomain&amp;quot;, MASTER_USER=&amp;quot;repl&amp;quot;, MASTER_PASSWORD=&amp;quot;IvIjyoffod2&amp;quot;;'&lt;br /&gt;
 &lt;br /&gt;
 # Oracle&lt;br /&gt;
 mysql -e &amp;quot;CHANGE MASTER TO MASTER_HOST='gtid-master.localdomain', MASTER_USER='repl', MASTER_PASSWORD='IvIjyoffod2', MASTER_AUTO_POSITION=1;&amp;quot;&lt;br /&gt;
 # https://www.percona.com/blog/2013/02/08/how-to-createrestore-a-slave-using-gtid-replication-in-mysql-5-6/&lt;br /&gt;
 mysql -e &amp;quot;RESET MASTER;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Read the master dump:&lt;br /&gt;
&lt;br /&gt;
 mysql &amp;lt; master.sql&lt;br /&gt;
&lt;br /&gt;
Start replication on the slave:&lt;br /&gt;
&lt;br /&gt;
 mysql -e 'START SLAVE;'&lt;br /&gt;
 mysql -e 'SHOW SLAVE STATUS\G'&lt;br /&gt;
&lt;br /&gt;
==== Master Setup (continued) ====&lt;br /&gt;
&lt;br /&gt;
Finally, unset read-only on the master:&lt;br /&gt;
&lt;br /&gt;
 # on the master&lt;br /&gt;
 mysql -e &amp;quot;SET @@global.read_only = OFF;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Configure OX to use with Master/Slave replication ===&lt;br /&gt;
&lt;br /&gt;
Not much special wisdom here. OX was designed to be used with master/slave databases. For the ConfigDB, &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt; allows configuration of a &amp;lt;code&amp;gt;readUrl&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;writeUrl&amp;lt;/code&amp;gt; (both of which are set to the correct values if you use &amp;lt;code&amp;gt;oxinstaller&amp;lt;/code&amp;gt; with the correct arguments &amp;lt;code&amp;gt;--configdb-readhost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--configdb-writehost&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
(Obviously, the master is for writing and the slave is for reading.)&lt;br /&gt;
&lt;br /&gt;
For the individiual UserDBs, use &amp;lt;code&amp;gt;registerdatabase -m true&amp;lt;/code&amp;gt; for the masters and &amp;lt;code&amp;gt;registerdatabase -m false -M ...&amp;lt;/code&amp;gt; for the respective slaves.&lt;br /&gt;
&lt;br /&gt;
Be sure to have enabled the replication monitor in &amp;lt;code&amp;gt;configdb.properties&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;com.openexchange.database.replicationMonitor=true&amp;lt;/code&amp;gt; (which it is by default); while GTID can show synchronous semantics, it is specified to silently fall back to asynchronous in certain circumstances, so synchronity is not guaranteed.&lt;br /&gt;
&lt;br /&gt;
We recommend, though, to not register the databases directly by their native hostname or IP, but rather use some kind of HA system in order to be able to easily move a floating/failover IP from the master to the slave in case of master failure. Configuring and running such systems (like, corosync/pacemaker, keepalived, or whatever) is out of scope of this documentation, however.&lt;br /&gt;
&lt;br /&gt;
== Creating Open-Xchange user ==&lt;br /&gt;
&lt;br /&gt;
Now setup access for the Open-Xchange Server database user 'openexchange' to configdb and the oxdb for both groupware server addresses. These databases do not exist yet, but will be created during the Open-Xchange Server installation.&lt;br /&gt;
&lt;br /&gt;
Note: The IPs in this example belong to the two different Open-Xchange Servers, please adjust them accordingly. And use a real password.&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt; GRANT ALL PRIVILEGES ON *.* TO 'openexchange'@'10.20.30.213' IDENTIFIED BY 'IntyoyntOat1';&lt;br /&gt;
 mysql&amp;gt; GRANT ALL PRIVILEGES ON *.* TO 'openexchange'@'10.20.30.215' IDENTIFIED BY 'IntyoyntOat1';&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=23790</id>
		<title>User:Dominik.epple</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=User:Dominik.epple&amp;diff=23790"/>
		<updated>2018-01-05T08:21:40Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Prepare database */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Install Guide ==&lt;br /&gt;
&lt;br /&gt;
=== About this document ===&lt;br /&gt;
&lt;br /&gt;
The aim of this document is to improve on the existing quickinstall guides to be more structured, provide a more extensive view on &amp;quot;single node and beyond&amp;quot; topics, follow closer to existing &amp;quot;best practices&amp;quot; (also, but not only security-wise), and point out what needs to be changed in clustered installations.&lt;br /&gt;
&lt;br /&gt;
Most of the commands given in this document thus assume a high level design of &amp;quot;single-node, all-in-one&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This document was created on Debian Stretch (which, as of time of writing, is not even supported yet), but it should work as-is also for jessie. Porting to RHEL/SLES/... is TODO.&lt;br /&gt;
&lt;br /&gt;
=== Preparations ===&lt;br /&gt;
&lt;br /&gt;
==== System update ====&lt;br /&gt;
&lt;br /&gt;
You want to start on latest patchlevel of your OS:&lt;br /&gt;
&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get dist-upgrade&lt;br /&gt;
 apt-get install less vim pwgen apt-transport-https&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
==== Pregenerate passwords ====&lt;br /&gt;
&lt;br /&gt;
This guide shall feature copy-paste ready commands which create installations with no default passwords.&lt;br /&gt;
&lt;br /&gt;
We will pre-generate some passwords which will live as dotfiles in /root.&lt;br /&gt;
&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.oxpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbpw&lt;br /&gt;
 pwgen -c -n 16 1 &amp;gt; /root/.dbrootpw&lt;br /&gt;
&lt;br /&gt;
==== Prepare database ====&lt;br /&gt;
&lt;br /&gt;
In real-world installations this will probably be multiple galera clusters of a supported flavor and version. For educational purposes a standalone DB on our single-node machine is sufficient.&lt;br /&gt;
&lt;br /&gt;
Even for single-node, don't forget to apply database tuning. See [[My.cnf|our oxpedia article]] for default tunings. Note that typically you need to re-initialize the MySQL datadir after changing InnoDB sizing values, and subsequently start the service:&lt;br /&gt;
&lt;br /&gt;
 mysql_install_db&lt;br /&gt;
 service mysql restart&lt;br /&gt;
&lt;br /&gt;
We aim to create secure-by-default documentation, so here we go: Run mysql_secure_installation, and chose every security relevant option, but let the root password empty in this step, as we set it in the next step:&lt;br /&gt;
&lt;br /&gt;
 # leave the root password empty in mysql_secure_installation as we set it in the subsequent step&lt;br /&gt;
 mysql_secure_installation&lt;br /&gt;
 # now, configure the password from /root/.dbrootpw&lt;br /&gt;
 mysql -e &amp;quot;UPDATE mysql.user SET Password=PASSWORD('$(cat /root/.dbrootpw)') WHERE User='root'; FLUSH PRIVILEGES;&amp;quot;&lt;br /&gt;
 cat &amp;gt;/root/.my.cnf &amp;lt;&amp;lt;EOF&lt;br /&gt;
 [client]&lt;br /&gt;
 user=root&lt;br /&gt;
 password=$(cat /root/.dbrootpw)&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
MySQL 5.7: the aforementioned must be adjusted using&lt;br /&gt;
&lt;br /&gt;
 ALTER USER USER() IDENTIFIED BY 'tiez7EiNgaish0ee';&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These credentials also needs to be put in /etc/mysql/debian.cnf.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
On multiple db clusters, do it per node analogously. Just be aware the copy-paste command above expects the /root/.dbrootpw file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare OX user ====&lt;br /&gt;
&lt;br /&gt;
While the packages will create the user automatically if it does not exist, we want to prepare the filestore now, and we need the user therefore.&lt;br /&gt;
&lt;br /&gt;
 useradd -r open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You should hard-wire the userid and groupid to the same fixed value. Otherwise, if you want to use a NFS filestore, you'll run into permissions problems, unless you use nfs4/kerberos/idmapd.&lt;br /&gt;
&lt;br /&gt;
 groupadd -r -g 999 open-xchange&lt;br /&gt;
 useradd -r -g 999 -u 999 open-xchange&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Prepare filestore ====&lt;br /&gt;
&lt;br /&gt;
There are several options here.&lt;br /&gt;
&lt;br /&gt;
===== Single-Node: local directory =====&lt;br /&gt;
&lt;br /&gt;
For a single-node installation, you can just prepare a local directory:&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
===== NFS =====&lt;br /&gt;
&lt;br /&gt;
If using NFS:&lt;br /&gt;
&lt;br /&gt;
Setup on the NFS server: &lt;br /&gt;
&lt;br /&gt;
 apt-get install nfs-kernel-server&lt;br /&gt;
 service nfs-kernel-server restart&lt;br /&gt;
&lt;br /&gt;
Configure /etc/exports. This is for traditional ip based access control; krb5 or other security configuration is out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 chown open-xchange:open-xchange /var/opt/filestore&lt;br /&gt;
 echo &amp;quot;/var/opt/filestore 192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)&amp;quot; &amp;gt;&amp;gt; /etc/exports&lt;br /&gt;
 exportfs -a&lt;br /&gt;
&lt;br /&gt;
Clients can then mount using&lt;br /&gt;
&lt;br /&gt;
 mkdir /var/opt/filestore&lt;br /&gt;
 mount -t nfs -o vers=4 nfs-server:/filestore /var/opt/filestore&lt;br /&gt;
&lt;br /&gt;
Or using fstab entries like&lt;br /&gt;
&lt;br /&gt;
 nfs-server:/filestore /var/opt/filestore nfs4 defaults 0 0&lt;br /&gt;
&lt;br /&gt;
===== Object Store =====&lt;br /&gt;
&lt;br /&gt;
You can use an object store. For lab environments Ceph is a convenient option. For demo / educational purpuses a &amp;quot;single node Ceph cluster&amp;quot; even co-located on your &amp;quot;single-node machine&amp;quot; is reasonble, but its setup is out of scope of this document. If you want to use this, be prepared to provide information about endpoint, bucket name, access key, secret key.&lt;br /&gt;
&lt;br /&gt;
===== No filestore =====&lt;br /&gt;
&lt;br /&gt;
If you dont want to provide a filestore, you can configure OX later to run without filestore. (Q: do we still need a dummy registerfilestore on a local directory in that event?)&lt;br /&gt;
&lt;br /&gt;
==== Prepare mail system ====&lt;br /&gt;
&lt;br /&gt;
Formally out of scope of this document.&lt;br /&gt;
&lt;br /&gt;
If you need to create a testing dovecot/postfix setup, you can use our [https://gitlab.open-xchange.com/qa/performance/tree/develop/com.openexchange.test.performance.gatling/src/site-preprocess/dovecot performance testing sample config].&lt;br /&gt;
&lt;br /&gt;
=== Install OX software ===&lt;br /&gt;
&lt;br /&gt;
You need an ldb user and password for updates and proprietary repos. If you dont have such a user, you can still install the free components. You'll get a lot of authentication failed warnings however from apt tools unless you deconfigure the closed repos.&lt;br /&gt;
&lt;br /&gt;
 wget http://software.open-xchange.com/oxbuildkey.pub -O - | apt-key add -&lt;br /&gt;
 wget -O/etc/apt/sources.list.d/ox.list http://software.open-xchange.com/products/DebianJessie.list&lt;br /&gt;
 ldbuser=...&lt;br /&gt;
 ldbpassword=...&lt;br /&gt;
 sed -i -e &amp;quot;s/LDBUSER:LDBPASSWORD/$ldbuser:$ldbpassword/&amp;quot; /etc/apt/sources.list.d/ox.list&lt;br /&gt;
 apt-get update&lt;br /&gt;
 apt-get install open-xchange open-xchange-authentication-database open-xchange-grizzly open-xchange-admin open-xchange-appsuite-backend open-xchange-appsuite-manifest open-xchange-appsuite&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
*if you want to have separate frontend (apache) and middleware (open-xchange) systems, make sure to install packages which require apache as dependency on the frontend nodes, and packages which require java as a dependency on the middleware nodes. Currently this results in the split&lt;br /&gt;
** Frontend nodes: open-xchange-appsuite&lt;br /&gt;
** Middleware nodes: everything else&lt;br /&gt;
* If you want to use an object store, install the corresponding open-xchange-filestore-xyz package, like open-xchange-filestore-s3&lt;br /&gt;
* For hazelcast session storage, install also open-xchange-sessionstorage-hazelcast&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Install database schemas ===&lt;br /&gt;
&lt;br /&gt;
If the DB runs on localhost and you have root access, you can use&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; -a&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cluster note&lt;br /&gt;
&lt;br /&gt;
Create the DB users on all write instances manually.&lt;br /&gt;
&lt;br /&gt;
 mysql -e &amp;quot;grant all privileges on *.* to 'openexchange'@'%' identified by '$(cat /root/.dbpw)';&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Run initconfigdb with some more options:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/initconfigdb --configdb-user=openexchange --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --configdb-host=configdb-writehost&lt;br /&gt;
&lt;br /&gt;
(initconfigdb needs to be run only once on one cluster node)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Initial configuration ===&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/oxinstaller --add-license=YOUR-OX-LICENSE-CODE --servername=oxserver --configdb-pass=&amp;quot;$(cat /root/.dbpw)&amp;quot; --master-pass=&amp;quot;$(cat /root/.oxpw)&amp;quot; --network-listener-host=localhost --servermemory 1024&lt;br /&gt;
&lt;br /&gt;
'''servername''' is more like a ''clustername'' and needs to be the same for all nodes.&lt;br /&gt;
&lt;br /&gt;
'''servermemory''' should be adjusted to reflect the expected number of concurrent active sessions; sizing assumption is 4MB per session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
 --configdb-readhost=...&lt;br /&gt;
 --configdb-writehost=...&lt;br /&gt;
 --imapserver=...&lt;br /&gt;
 --smtpserver=...&lt;br /&gt;
 --mail-login-src=&amp;lt;login|mail|name&amp;gt;&lt;br /&gt;
 --mail-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --transport-server-src=&amp;lt;user|global&amp;gt;&lt;br /&gt;
 --jkroute=APP1&lt;br /&gt;
 --object-link-hostname=[service DNS name like ox.example.com]&lt;br /&gt;
 --extras-link=[https://ox.example.com/]&lt;br /&gt;
 --name-of-oxcluster=[something unique per cluster, like business-staging; see --servername]&lt;br /&gt;
 --network-listener-host=&amp;lt;localhost|*&amp;gt;&lt;br /&gt;
&lt;br /&gt;
oxinstaller needs to be run on each cluster node with identical options besides the jkroute, which must be unique per cluster node and match the corresponding apache option, see below.&lt;br /&gt;
&lt;br /&gt;
In a cluster you also want to configure hazelcast; see [[AppSuite:Running_a_cluster#Configuration]]. Most prominent options are &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.enabled=true&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&amp;lt;reasonable unique group name&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.group.password=&amp;lt;unique password, CHANGE THE SHIPPED DEFAULT PASSWORD!&amp;gt;&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static # static is recommended over multicast for robustness&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=... # configure your nodes as a comma-separated list; a bootstrapping subset is acceptable&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=... # pick your subnet;  Wildcards (*) and ranges (-) can be used&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Start the service:&lt;br /&gt;
&lt;br /&gt;
 systemctl restart open-xchange&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Start the service on every cluster node.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registering stuff ===&lt;br /&gt;
&lt;br /&gt;
Register the &amp;quot;server&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerserver -n oxserver -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
All the register* commands need to be issued only once per cluster, as the effect is to enter corresponding lines in the configdb.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the filestore:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t file:/var/opt/filestore -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
If you chose an object store, the corresponding registerfilestore line reads as follows (Ceph radosgw example):&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -t s3://radosgw -s 1000000 -x 1000000&lt;br /&gt;
&lt;br /&gt;
It requires configuration of the object store in filestore-s3.properties:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.endpoint=http://localhost:7480&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.bucketName=oxbucket&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.region=eu-west-1&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.pathStyleAccess=true&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.accessKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.secretKey=...&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.encryption=none&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.signerOverride=S3SignerType&lt;br /&gt;
 com.openexchange.filestore.s3.radosgw.chunkSize=5MB&lt;br /&gt;
&lt;br /&gt;
Changing this file needs another&lt;br /&gt;
&lt;br /&gt;
 service open-xchange restart&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And the database:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
You probably have multiple clusters with read and write URLs. Register them each like first registering the master, subsequently registering the slave URL with the corresponding master ID:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdb -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m true&lt;br /&gt;
&lt;br /&gt;
This command gives as output the id of the registered db master, like&lt;br /&gt;
&lt;br /&gt;
 database 3 registered&lt;br /&gt;
&lt;br /&gt;
Here, the id is 3. Use this id as argument of the -M switch of the next command:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P &amp;quot;$(cat /root/.oxpw)&amp;quot; -n oxdbr -p &amp;quot;$(cat /root/.dbpw)&amp;quot; -m false -M 3&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Configure Apache ===&lt;br /&gt;
&lt;br /&gt;
Create config files /etc/apache2/conf-enabled/proxy_http.conf, /etc/apache2/sites-enabled/000-default.conf by copy-pasting as explained in [[AppSuite:Open-Xchange_Installation_Guide_for_Debian_8.0#Configure_services]]&lt;br /&gt;
&lt;br /&gt;
Make sure you are using mpm_event. Apply concurrent connections tuning as described in [[Tune_apache2_for_more_concurrent_connections]].&lt;br /&gt;
&lt;br /&gt;
Configure modules and restart:&lt;br /&gt;
&lt;br /&gt;
 a2enmod proxy proxy_http proxy_balancer expires deflate headers rewrite mime setenvif lbmethod_byrequests&lt;br /&gt;
 systemctl restart apache2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 20px; border-style: solid; border-width: thin;&amp;quot;&amp;gt;&lt;br /&gt;
Cluster Note&lt;br /&gt;
&lt;br /&gt;
Make sure that each middleware node got its unique server.properties:com.openexchange.server.backendRoute, e.g. APP1, APP2, APP3, etc.&lt;br /&gt;
&lt;br /&gt;
Configure them in the http proxy definitions like&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP3&lt;br /&gt;
&lt;br /&gt;
If you colocate apache on middleware nodes, you might want to minimize cross-node routing, by setting on each node for the local node a loadfactor=50 and for the other nodes a status=+H instead of the loadfactor. E.g. on node ox1:&lt;br /&gt;
&lt;br /&gt;
 BalancerMember http://ox1:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1&lt;br /&gt;
 BalancerMember http://ox2:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP2&lt;br /&gt;
 BalancerMember http://ox3:8009 timeout=100 smax=0 ttl=60 retry=60 status=+H route=APP3&lt;br /&gt;
&lt;br /&gt;
However this requires host-specific config files for apache http proxy.&lt;br /&gt;
&lt;br /&gt;
Use touch-appsuite with one identical timestamp on each frontend node.&lt;br /&gt;
&lt;br /&gt;
 timestamp=$(date -u +%Y%m%d.%H%M%S)&lt;br /&gt;
 for node in $all_frontend_nodes; do&lt;br /&gt;
     ssh $node /opt/open-xchange/sbin/touch-appsuite --timestamp=$timestamp&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Provision a  Test User ===&lt;br /&gt;
&lt;br /&gt;
Provision a sample context and user:&lt;br /&gt;
&lt;br /&gt;
 /opt/open-xchange/sbin/createcontext  -c 1 -A oxadminmaster -P secret -N localdomain -u oxadmin -d &amp;quot;Admin User&amp;quot; -g Admin -s User -p secret -e oxadmin@localdomain -q 100 --access-combination-name groupware_premium&lt;br /&gt;
 /opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P secret -u testuser -d &amp;quot;Test User&amp;quot; -g Test -s User -p secret -e testuser@localdomain --access-combination-name groupware_premium&lt;br /&gt;
&lt;br /&gt;
[[Context_Preprovisioning#Sample_Script]] provides an example how to fast-mode provision a huge number of contexts quickly.&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Running_a_cluster&amp;diff=23789</id>
		<title>AppSuite:Running a cluster</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Running_a_cluster&amp;diff=23789"/>
		<updated>2017-12-13T08:10:58Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Rolling Upgrade without breaking Hazelcast upgrade */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Running a cluster&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Concepts =&lt;br /&gt;
&lt;br /&gt;
For inter-OX-communication over the network, multiple Open-Xchange servers can form a cluster. This brings different advantages regarding distribution and caching of volatile data, load balancing, scalability, fail-safety and robustness. Additionally, it provides the infrastructure for upcoming features of the Open-Xchange server. &lt;br /&gt;
The clustering capabilities of the Open-Xchange server are mainly built up on [http://hazelcast.com Hazelcast], an open source clustering and highly scalable data distribution platform for Java. The following article provides an overview about the current featureset and configuration options.&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
== Synchronized system clock times ==&lt;br /&gt;
It is crucial that all involved members in a cluster do have their system clock times in sync with each other; e.g. by using an NTP service.&lt;br /&gt;
&lt;br /&gt;
== HTTP routing ==&lt;br /&gt;
An OX cluster is always part of a larger picture. Usually there is front level loadbalancer as central HTTPS entry point to the platform. This loadbalancer optionally performs HTTPS termination and forwards HTTP(S) requests to webservers (the usual and only supported choice as of now is Apache). These webservers are performing HTTPS termination (if this is not happening on the loadbalancer) and serve static content, and (which is what is relevant for our discussion here) they forward dynamic requests to the OX backends.&lt;br /&gt;
&lt;br /&gt;
A central requirement for the interaction of these components (loadbalancer, webservers, OX nodes) is that we have session stability based on the JSESSIONID cookie / jsessionid path component suffix. This means that our application sets a cookie named JSESSIONID which has a value like &amp;lt;large decimal number&amp;gt;.&amp;lt;route identifier&amp;gt;, e.g. &amp;quot;5661584529655240315.OX1&amp;quot;. The route identifier here (&amp;quot;OX1&amp;quot; in this example) is taken by the OX node from a configuration setting from a config file and is specific to one OX node. HTTP routing must happen such that HTTP requests with a cookie with such a suffix always end up the corresponding OX node. There are furthermore specific cirumstances when passing this information via cookie is not possible. Then the JSESSIONID is transferred in a path component as &amp;quot;jsessionid=...&amp;quot; in the HTTP request. The routing mechanism needs to take that into account also.&lt;br /&gt;
&lt;br /&gt;
There are mainly two options to implement this. If the Apache processes are running co-located on the same machines running the OX groupware processes, it is often desired to have the front level loadbalancer perform HTTP routing to the correct machines. If dedicated Apache nodes are employed, is is usually sufficient to have the front-level loadbalancer do HTTP routing to the Apache nodes in a round-robin fashion and perform routing to the correct OX nodes in the Apache nodes.&lt;br /&gt;
&lt;br /&gt;
We provide sample configuration files to configure Apache (with mod_proxy_http) to perform HTTP routing correctly in our guides on OXpedia, e.g. [[AppSuite:Main_Page_AppSuite#quickinstall]]. Central elements are the directives &amp;quot;ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&amp;quot; in conjunction with the &amp;quot;route=OX1&amp;quot; parameters to the BalancerMember lines in the Proxy definition. This is valid for Apache 2.2 as of Sep-2014.&lt;br /&gt;
&lt;br /&gt;
How to configure a front level loadbalancer to perform HTTP equivalent HTTP routing is dependent on the specific loadbalancer implementation. If Apache is used as front level loadbalancer, the same configuration as discussed in the previous section can be employed. As of time of writing this text (Sep 2014), the alternative choices are thin. F5 BigIP is reported to be able to implement &amp;quot;jsessionid based persistence using iRules&amp;quot;. nginx has the functionality in their commercial &amp;quot;nginx plus&amp;quot; product. (Both of these options have not been tested by OX.) Other loadbalancers with this functionality are not known to us.&lt;br /&gt;
&lt;br /&gt;
If the front level loadbalancer is not capable of performing correct HTTP routing, is is required to configure correct HTTP routing on Apache level, even if Apache runs co-located on the OX nodes and thus cross-routing happens.&lt;br /&gt;
&lt;br /&gt;
There are several reasons why we require session stability in exactly this way. We require session stabilty for horizontal scale-out; while we support transparent resuming / migration of user sessions in the OX cluster without need for users to re-authenticate, sessions wandering around randomly will consume a fixed amount resources corresponding to a running session on each OX node in the cluster, while a session sticky to one OX node will consume this fixed amount of resources only on one OX node. Furthermore there are mechanisms in OX like TokenLogin which work only of all requests beloning to one sequence get routed to the same OX node even if they stem from different machines with different IPs. Only the JSESSIONID (which in this case is transferred as jsessionid path component, as cookies do not work during a 302 redirect, which is part of this sequence) carries the required information where the request must be routed to.&lt;br /&gt;
&lt;br /&gt;
Usual &amp;quot;routing based on cookie hash&amp;quot; is not sufficient here since it disregards the information which machine originally issued the cookie. It only ensures that the session will be sticky to any target, which statistically will not be the same machine that issued the cookie. OX will then set a new JSESSIONID cookie, assuming the session had been migrated. The loadbalancer will then route the session to a different target, as the hash of the cookie will differ. This procedure then happens iteratively until by chance the routing based on cookie hash will route the session to the correct target. By then, a lot of resources will have been wasted, by creating full (short-term) sessions on all OX nodes. Furthermore, processes like TokenLogin will not work this way.&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
&lt;br /&gt;
All settings regarding cluster setup are located in the configuration file ''hazelcast.properties''. The former used additional files ''cluster.properties'', ''mdns.properties'' and ''static-cluster-discovery.properties'' are no longer needed. The following gives an overview about the most important settings - please refer to the inline documentation of the configuration file for more advanced options.&lt;br /&gt;
&lt;br /&gt;
Note: The configuration guide targets v7.4.0 of the OX server (and above). For older versions, please consult the history of this page. A full list of Hazelcast-related properties is available at https://documentation.open-xchange.com/components/middleware/config/7.8.4/#mode=features&amp;amp;feature=Hazelcast .&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
To restrict access to the cluster and to separate the cluster from others in the local network, a name and password needs to be defined. Only backend nodes having the same values for those properties are able to join and form a cluster. &lt;br /&gt;
&lt;br /&gt;
 # Configures the name of the cluster. Only nodes using the same group name &lt;br /&gt;
 # will join each other and form the cluster. Required if &lt;br /&gt;
 # &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is not &amp;quot;empty&amp;quot; (see below).&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&lt;br /&gt;
 &lt;br /&gt;
 # The password used when joining the cluster. Defaults to &amp;quot;wtV6$VQk8#+3ds!a&amp;quot;. &lt;br /&gt;
 # Please change this value, and ensure it's equal on all nodes in the cluster.&lt;br /&gt;
 com.openexchange.hazelcast.group.password=wtV6$VQk8#+3ds!a&lt;br /&gt;
&lt;br /&gt;
== Network ==&lt;br /&gt;
&lt;br /&gt;
It's required to define the network interface that is used for cluster communication via ''com.openexchange.hazelcast.network.interfaces''. By default, the interface is restricted to the local loopback address only. To allow the same configuration amongst all nodes in the cluster, it's recommended to define the value using a wildcard matching the IP addresses of all nodes participating in the cluster, e.g. ''192.168.0.*''&lt;br /&gt;
&lt;br /&gt;
 # Comma-separated list of interface addresses hazelcast should use. Wildcards &lt;br /&gt;
 # (*) and ranges (-) can be used. Leave blank to listen on all interfaces&lt;br /&gt;
 # Especially in server environments with multiple network interfaces, it's &lt;br /&gt;
 # recommended to specify the IP-address of the network interface to bind to &lt;br /&gt;
 # explicitly. Defaults to &amp;quot;127.0.0.1&amp;quot; (local loopback only), needs to be &lt;br /&gt;
 # adjusted when building a cluster of multiple backend nodes.&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=127.0.0.1&lt;br /&gt;
&lt;br /&gt;
To form a cluster of multiple OX server nodes, different discovery mechanisms can be used. The discovery mechanism is specified via the property ''com.openexchange.hazelcast.network.join'':&lt;br /&gt;
&lt;br /&gt;
 # Specifies which mechanism is used to discover other backend nodes in the &lt;br /&gt;
 # cluster. Possible values are &amp;quot;empty&amp;quot; (no discovery for single-node setups),&lt;br /&gt;
 # &amp;quot;static&amp;quot; (fixed set of cluster member nodes) or &amp;quot;multicast&amp;quot; (automatic &lt;br /&gt;
 # discovery of other nodes via multicast). Defaults to &amp;quot;empty&amp;quot;. Depending on &lt;br /&gt;
 # the specified value, further configuration might be needed, see &amp;quot;Networking&amp;quot;&lt;br /&gt;
 # section below. &lt;br /&gt;
 com.openexchange.hazelcast.network.join=empty&lt;br /&gt;
&lt;br /&gt;
Generally, it's advised to use the same network join mechanism for all nodes in the cluster, and, in most cases, it's strongly recommended to use a ''static'' network join configuration. This will allow the nodes to join the cluster directly upon startup. With a ''multicast'' based setup, nodes will merge to an existing cluster possibly at some later time, thus not being able to access the distributed data until they've joined.&lt;br /&gt;
&lt;br /&gt;
Depending on the network join setting, further configuration may be necessary, as decribed in the following paragraphs.&lt;br /&gt;
&lt;br /&gt;
=== empty ===&lt;br /&gt;
&lt;br /&gt;
When using the default value ''empty'', no other nodes are discovered in the cluster. This value is suitable for single-node installations. Note that other nodes that are configured to use other network join mechanisms may be still able to still to connect to this node, e.g. using a ''static'' network join, having the IP address of this host in the list of potential cluster members (see below).&lt;br /&gt;
&lt;br /&gt;
=== static ===&lt;br /&gt;
&lt;br /&gt;
The most common setting for ''com.openexchange.hazelcast.network.join'' is ''static''. A static cluster discovery uses a fixed list of IP addresses of the nodes in the cluster. During startup and after a specific interval, the underlying Hazelcast library probes for not yet joined nodes from this list and adds them to the cluster automatically. The address list is configured via ''com.openexchange.hazelcast.network.join.static.nodes'':&lt;br /&gt;
&lt;br /&gt;
 # Configures a comma-separated list of IP addresses / hostnames of possible &lt;br /&gt;
 # nodes in the cluster, e.g. &amp;quot;10.20.30.12, 10.20.30.13:5701, 192.178.168.110&amp;quot;.&lt;br /&gt;
 # Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set to &amp;quot;static&amp;quot;. &lt;br /&gt;
 # It doesn't hurt if the address of the local host appears in the list, so &lt;br /&gt;
 # that it's still possible to use the same list throughout all nodes in the &lt;br /&gt;
 # cluster.&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=&lt;br /&gt;
&lt;br /&gt;
For a fixed set of backend nodes, it's recommended to simply include the IP addresses of all nodes in the list, and use the same configuration for each node. However, it's only required to add the address of at least one other node in the cluster to allow the node to join the cluster. Also, when adding a new node to the cluster and this list is extended accordingly, existing nodes don't need to be shut down to recognize the new node, as long as the new node's address list contains at least one of the already running nodes. &lt;br /&gt;
&lt;br /&gt;
=== multicast ===&lt;br /&gt;
&lt;br /&gt;
For highly dynamic setups where nodes are added and removed from the cluster quite often and/or the host's IP addresses are not fixed, it's also possible to configure the network join via multicast. During startup and after a specific interval, the backend nodes initiate the multicast join process automatically, and discovered nodes form or join the cluster afterwards. The multicast group and port can be configured as follows:&lt;br /&gt;
&lt;br /&gt;
 # Configures the multicast address used to discover other nodes in the cluster&lt;br /&gt;
 # dynamically. Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set &lt;br /&gt;
 # to &amp;quot;multicast&amp;quot;. If the nodes reside in different subnets, please ensure that &lt;br /&gt;
 # multicast is enabled between the subnets. Defaults to &amp;quot;224.2.2.3&amp;quot;. &lt;br /&gt;
 com.openexchange.hazelcast.network.join.multicast.group=224.2.2.3&lt;br /&gt;
 &lt;br /&gt;
 # Configures the multicast port used to discover other nodes in the cluster&lt;br /&gt;
 # dynamically. Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set &lt;br /&gt;
 # to &amp;quot;multicast&amp;quot;. Defaults to &amp;quot;54327&amp;quot;. &lt;br /&gt;
 com.openexchange.hazelcast.network.join.multicast.port=54327&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
&lt;br /&gt;
The following example shows how a simple cluster named ''MyCluster'' consisting of 4 backend nodes can be configured using ''static'' cluster discovery. The node's IP addresses are 10.0.0.15, 10.0.0.16, 10.0.0.17 and 10.0.0.18. Note that the same ''hazelcast.properties'' is used by all nodes.&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.group.name=MyCluster&lt;br /&gt;
 com.openexchange.hazelcast.group.password=secret&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=10.0.0.15,10.0.0.16,10.0.0.17,10.0.0.18&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=10.0.0.*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Advanced Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== Lite Members (available since v7.8.4) ===&lt;br /&gt;
&lt;br /&gt;
Lite members in a Hazelcast cluster are members that do not hold any data partitions, i.e. all read- and write operations to distributed maps are delegated to non-lite (&amp;quot;full&amp;quot;) members. Apart from not having data partitions, lite members participate in the same way as other members: they can register listeners for distributed topics (e.g. cache invalidation events) or can be addressed for task execution (e.g. during realtime communication). &lt;br /&gt;
&lt;br /&gt;
Similar to using a custom partitioning scheme, separating the nodes of a large cluster into few &amp;quot;full&amp;quot; members and many &amp;quot;lite&amp;quot; members helps to minimize the impact of JVM activities from a single node (mainly the garbage collector) on the whole cluster communication. Additionally, when starting or stopping lite members, no repartitioning of the distributed cluster data needs to be performed, which significantly decreases the node's startup- and shutdown time and reduces the necessary network communication to a minimum. &lt;br /&gt;
&lt;br /&gt;
In medium or larger sized clusters, it is sufficient to have roughly 10 to 20 percent of the nodes configured as &amp;quot;full&amp;quot; members, while all other ones can be started as &amp;quot;lite&amp;quot; member nodes. Additionally, please note that the configured backup count in the map configurations should always be smaller than the total number of &amp;quot;full&amp;quot; members, otherwise, there may be problems if one of those data nodes is shut down temporarily for maintenance. So, the minimum number of &amp;quot;full&amp;quot; members is implicitly bound to the sum of a map's ''backupCount'' and ''asyncBackupCount'' properties, plus ''1'' for the original data partition. &lt;br /&gt;
&lt;br /&gt;
The configured &amp;quot;full&amp;quot; members should preferrably not be used to serve client requests (by not adding them as endpoint in the loadbalancer), to ensure they are always responsive. Also, shutdown and startups of those &amp;quot;full&amp;quot; members should be reduced to a minimum to avoid repartitioning operations. &lt;br /&gt;
&lt;br /&gt;
More general information regarding lite members is available at http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#enabling-lite-members .&lt;br /&gt;
&lt;br /&gt;
To configure a node as &amp;quot;lite&amp;quot; member, the following configuration should be applied in the node's ''hazelcast.properties'' file:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.liteMember=true&lt;br /&gt;
&lt;br /&gt;
It's also recommended to use a &amp;quot;static&amp;quot; cluster discovery for the network join, and list all &amp;quot;full&amp;quot; member nodes here, so that join requests are handled by those nodes, too (and not the other nodes that are potentially prone to garbage collection delays. &lt;br /&gt;
&lt;br /&gt;
=== Custom Partitioning ===&lt;br /&gt;
&lt;br /&gt;
Note: Starting with v7.8.4, &amp;quot;Lite Members&amp;quot; should be used in favor of applying a custom partitioning scheme.&lt;br /&gt;
&lt;br /&gt;
While originally being designed to separate the nodes holding distributed data into different risk groups for increased fail safety, a custom partitioning strategy may also be used to distinguish between nodes holding distributed data from those who should not. &lt;br /&gt;
&lt;br /&gt;
This approach of custom partitioning may be used in a OX cluster, where usually different backend nodes serve different purposes. A common scenario is that there are nodes handling requests from the web interfaces, and others being responsible for USM/EAS traffic. Due to their nature of processing large chunks of synchronization data in memory, the USM/EAS nodes may encounter small delays when the Java garbage collector kicks in and suspends the Java Virtual Machine. Since those delays may also have an influence on hazelcast-based communication in the cluster, the idea is to instruct hazelcast to not store distributed data on that nodes. This is where a custom partitioning scheme comes into play.&lt;br /&gt;
&lt;br /&gt;
To setup a custom partitioning scheme in the cluster, an additional ''hazelcast.xml'' configuration file is used, which should be placed into the ''hazelcast'' subdirectory of the OX configuration folder, usually at ''/opt/openexchange/etc/hazelcast''. Please note that it's vital that each node in the cluster is configured equally here, so the same ''hazelcast.xml'' file should be copied to each server. The configuration read from there is used as basis for all further settings that are taken from the ordinary ''hazelcast.properties'' config file. &lt;br /&gt;
&lt;br /&gt;
To setup a custom partitioning scheme, the partition groups must be defined in the ''hazelcast.xml'' file. See the following file for an example configuration, where the three nodes ''10.10.10.60'', ''10.10.10.61'' and ''10.10.10.62'' are defined to form an own partitioning group each. Doing so, all distributed data will be stored at one of those nodes physically, while the corresponding backup data (if configured) at one of the other two nodes. All other nodes in the cluster will not be used to store distributed data, but will still be &amp;quot;full&amp;quot; hazelcast members, which is necessary for other cluster-wide operations the OX backends use. &lt;br /&gt;
&lt;br /&gt;
Please note that the configured backup count in the map configurations should be smaller than the number of nodes here, otherwise, there may be problems if one of those data nodes is shut down temporarily for maintenance. So, the minimum number of nodes to define in the partition group sections is implicitly bound to the sum of a map's ''backupCount'' and ''asyncBackupCount'' properties, plus ''1'' for the original data partition. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
 &amp;lt;!--&lt;br /&gt;
   ~ Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.&lt;br /&gt;
   ~&lt;br /&gt;
   ~ Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
   ~ you may not use this file except in compliance with the License.&lt;br /&gt;
   ~ You may obtain a copy of the License at&lt;br /&gt;
   ~&lt;br /&gt;
   ~ http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
   ~&lt;br /&gt;
   ~ Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
   ~ distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
   ~ See the License for the specific language governing permissions and&lt;br /&gt;
   ~ limitations under the License.&lt;br /&gt;
   --&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;hazelcast xsi:schemaLocation=&amp;quot;http://www.hazelcast.com/schema/config hazelcast-config-3.1.xsd&amp;quot;&lt;br /&gt;
            xmlns=&amp;quot;http://www.hazelcast.com/schema/config&amp;quot;&lt;br /&gt;
            xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;partition-group enabled=&amp;quot;true&amp;quot; group-type=&amp;quot;CUSTOM&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.60&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.61&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.62&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
     &amp;lt;/partition-group&amp;gt;&lt;br /&gt;
 &amp;lt;/hazelcast&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More general information regarding custom partioning is available at http://hazelcast.org/docs/latest/manual/html/partitiongroupconfig.html . &lt;br /&gt;
&lt;br /&gt;
It's also recommended to use a &amp;quot;static&amp;quot; cluster discovery for the network join, and list same the nodes that are also configured in the parition groups here, so that join requests are handled by those nodes, too (and not the other nodes that are potentially prone to garbage collection delays. &lt;br /&gt;
&lt;br /&gt;
After configuring a custom partitioning scheme, the data distribution may be verified, e.g. by inspecting the MBeans of the distributed maps via JMX.&lt;br /&gt;
&lt;br /&gt;
= Features =&lt;br /&gt;
&lt;br /&gt;
The following list gives an overview about different features that were implemented using the new cluster capabilities.&lt;br /&gt;
&lt;br /&gt;
== Distributed Session Storage ==&lt;br /&gt;
&lt;br /&gt;
Previously, when an Open-Xchange server was shutdown for maintenance, all user sessions that were bound to that machine were lost, i.e. the users needed to login again. With the distributed session storage, all sessions are backed by a distributed map in the cluster, so that they are no longer bound to a specific node in the cluster. When a node is shut down, the session data is still available in the cluster and can be accessed from the remaining nodes. The load-balancing techniques of the webserver then seamlessly routes the user session to another node, with no ''session expired'' errors. The distributed session storage comes with the package ''open-xchange-sessionstorage-hazelcast''. It's recommended to install this optional package in all clustered environments with multiple groupware server nodes.&lt;br /&gt;
&lt;br /&gt;
'''Notes:''' &lt;br /&gt;
* While there's some kind of built-in session distribution among the nodes in the cluster, this should not be seen as a replacement for session-stickiness between the loadbalancer and groupware nodes, i.e. one should still configure the webserver to use sticky sessions for performance reasons.&lt;br /&gt;
* The distributed session storage is still an in-memory storage. While the session data is distributed and backed up on multiple nodes in the cluster, shutting down multiple or all nodes at the same time will lead to loss of the the distributed data. To avoid such data loss when shutting down a node, please follow the guidelines at [[ Updating_a_Cluster ]].&lt;br /&gt;
&lt;br /&gt;
Depending on the cluster infrastructure, different backup-count configuration options might be set for the distributed session storage in the map configuration file ''sessions.properties'' in the ''hazelcast'' subdirectory:&lt;br /&gt;
&lt;br /&gt;
   com.openexchange.hazelcast.configuration.map.backupCount=1&lt;br /&gt;
&lt;br /&gt;
The ''backupcount'' property configures the number of nodes with synchronized backups. Synchronized backups block operations until backups are successfully copied and acknowledgements are received. If 1 is set as the backup-count for example, then all entries of the map will be copied to another JVM for fail-safety. 0 means no backup. Any integer between 0 and 6. Default is 1, setting bigger than 6 has no effect.&lt;br /&gt;
&lt;br /&gt;
   com.openexchange.hazelcast.configuration.map.asyncBackupCount=0&lt;br /&gt;
&lt;br /&gt;
The ''asyncbackup'' property configures the number of nodes with async backups. Async backups do not block operations and do not require acknowledgements. 0 means no backup. Any integer between 0 and 6. Default is 0, setting bigger than 6 has no effect.&lt;br /&gt;
&lt;br /&gt;
Since session data is backed up by default continuously by multiple nodes in the cluster, the steps described in [[ Session_Migration ]] to trigger session migration to other nodes explicitly is obsolete and no longer needed with the distributed session storage.&lt;br /&gt;
&lt;br /&gt;
Normally, sessions in the distributed storages are not evicted automatically, but are only removed when they're also removed from the session handler, either due to a logout operation or when exceeding the long-term session lifetime as configured by ''com.openexchange.sessiond.sessionLongLifeTime'' in ''sessiond.properties''. Under certain circumstances, i.e. the session is no longer accessed by the client and the OX node hosting the session in it's long-life container being shutdown, the remove operation from the distributed storage might not be triggered. Therefore, additionaly a maximum idle time of map-entries can be configured for the distributed sessions map via &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.configuration.map.maxIdleSeconds=640000&lt;br /&gt;
&lt;br /&gt;
To avoid unnecessary eviction, the value should be higher than the configured ''com.openexchange.sessiond.sessionLongLifeTime'' in ''sessiond.properties''.&lt;br /&gt;
&lt;br /&gt;
== Remote Cache Invalidation ==&lt;br /&gt;
&lt;br /&gt;
For faster access, groupware data is held in different caches by the server. Formerly, the caches utilized the TCP Lateral Auxiliary Cache plug in (LTCP) for the underlying JCS caches to broadcast updates and removals to caches on other OX nodes in the cluster. This could potentially lead to problems when remote invalidation was not working reliably due to network discovery problems. As an alternative, remote cache invalidation can also be performed using reliable publish/subscribe events built up on Hazelcast topics. This can be configured in the ''cache.properties'' configuration file, where the 'eventInvalidation' property can either be set to 'false' for the legacy behavior or 'true' for the new mechanism:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.caching.jcs.eventInvalidation=true&lt;br /&gt;
&lt;br /&gt;
All nodes participating in the cluster should be configured equally.&lt;br /&gt;
&lt;br /&gt;
Internally, if ''com.openexchange.caching.jcs.eventInvalidation'' is set to ''true'', LTCP is disabled in JCS caches. Instead, an internal mechanism based on distributed Hazelcast event topics is used to invalidate data throughout all nodes in the cluster after local update- and remove-operations. Put-operations aren't propagated (and haven't been with LTCP either), since all data put into caches can be locally loaded/evaluated at each node from the persistent storage layer.&lt;br /&gt;
&lt;br /&gt;
Using Hazelcast-based cache invalidation also makes further configuration of the JCS auxiliaries obsolete in the ''cache.ccf'' configuration file. In that case, all ''jcs.auxiliary.LTCP.*'' configuration settings are virtually ignored. However, it's still required to mark caches that require cluster-wide invalidation via ''jcs.region.&amp;lt;cache_name&amp;gt;=LTCP'', just as before. So basically, when using the new default setting ''com.openexchange.caching.jcs.eventInvalidation=true'', it's recommended to just use the stock ''cache.ccf'' file, since no further LTCP configuration is required.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
= Adminstration / Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
== Hazelcast Configuration ==&lt;br /&gt;
&lt;br /&gt;
The underlying Hazelcast library can be configured using the file ''hazelcast.properties''.&lt;br /&gt;
&lt;br /&gt;
'''Important''':&amp;lt;br&amp;gt;&lt;br /&gt;
By default property ''com.openexchange.hazelcast.network.interfaces'' is set to ''127.0.0.1''; meaning Hazelcast listens only to loop-back device. To build a cluster among remote nodes the appropriate network interface needs to be configured there. Leaving that property empty lets Hazelcast listen to all available network interfaces.&lt;br /&gt;
&lt;br /&gt;
The Hazelcast JMX MBean can be enabled or disabled with the property ''com.openexchange.hazelcast.jmx''. The properties ''com.openexchange.hazelcast.mergeFirstRunDelay'' and ''com.openexchange.hazelcast.mergeRunDelay'' control the run intervals of the so-called ''Split Brain Handler'' of Hazelcast that initiates the cluster join process when a new node is started. More details can be found at http://www.hazelcast.com/docs/2.5/manual/single_html/#NetworkPartitioning. &lt;br /&gt;
&lt;br /&gt;
The port ranges used by Hazelcast for incoming and outgoing connections can be controlled via the configuration parameters ''com.openexchange.hazelcast.networkConfig.port'', ''com.openexchange.hazelcast.networkConfig.portAutoIncrement'' and ''com.openexchange.hazelcast.networkConfig.outboundPortDefinitions''.&lt;br /&gt;
&lt;br /&gt;
== Commandline Tool ==&lt;br /&gt;
&lt;br /&gt;
To print out statistics about the cluster and the distributed data, the ''showruntimestats'' commandline tool can be executed witht the ''clusterstats'' ('c') argument. This provides an overview about the runtime cluster configuration of the node, other members in the cluster and distributed data structures.&lt;br /&gt;
&lt;br /&gt;
== JMX ==&lt;br /&gt;
&lt;br /&gt;
In the Open-Xchange server Java process, the MBean ''com.hazelcast'' can be used to monitor and manage different aspects of the underlying Hazelcast cluster. The ''com.hazelcast'' MBean provides detailed information about the cluster configuration and distributed data structures.&lt;br /&gt;
&lt;br /&gt;
== Hazelcast Errors ==&lt;br /&gt;
&lt;br /&gt;
When experiencing hazelcast related errors in the logfiles, most likely different versions of the packages are installed, leading to different message formats that can't be understood by nodes using another version. Examples for such errors are exceptions in hazelcast components regarding (de)serialization or other message processing.&lt;br /&gt;
This may happen when performing a consecutive update of all nodes in the cluster, where temporarily nodes with a heterogeneous setup try to communicate with each other. If the errors don't disappear after all nodes in the cluster have been update to the same package versions, it might be necessary to shutdown the cluster completely, so that all distributed data is cleared.&lt;br /&gt;
&lt;br /&gt;
== Cluster Discovery Errors ==&lt;br /&gt;
&lt;br /&gt;
* If the started OX nodes don't form a cluster, please double-check your configuration in ''hazelcast.properties''&lt;br /&gt;
* It's important to have the same cluster name defined in ''hazelcast.properties'' throughout all nodes in the cluster&lt;br /&gt;
* Especially when using multicast cluster discovery, it might take some time until the cluster is formed&lt;br /&gt;
* When using ''static'' cluster discovery, at least one other node in the cluster has to be configured in ''com.openexchange.hazelcast.network.join.static.nodes'' to allow joining, however, it's recommended to list all nodes in the cluster here&lt;br /&gt;
&lt;br /&gt;
== Disable Cluster Features ==&lt;br /&gt;
&lt;br /&gt;
The Hazelcast based clustering features can be disabled with the following property changes:&lt;br /&gt;
* Disable cluster discovery by setting ''com.openexchange.hazelcast.network.join'' to ''empty'' in ''hazelcast.properties''&lt;br /&gt;
* Disable Hazelcast by setting ''com.openexchange.hazelcast.enabled'' to false in ''hazelcast.properties''&lt;br /&gt;
* Disable message based cache event invalidation by setting ''com.openexchange.caching.jcs.eventInvalidation'' to ''false'' in ''cache.properties''&lt;br /&gt;
&lt;br /&gt;
== Update from 6.22.1 to version 6.22.2 and above ==&lt;br /&gt;
&lt;br /&gt;
As hazelcast will be used by default for the distribution of sessions starting 6.22.2 you have to adjust hazelcast according to our old cache configuration. First of all it's important that you install the open-xchange-sessionstorage-hazelcast package. This package will add the binding between hazelcast and the internal session management. Next you have to set a cluster name to the cluster.properties file (see [[#Cluster Discovery Errors]]). Furthermore you will have to add one of the two discovery modes mentioned in [[#Cluster Discovery]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Updating a Cluster =&lt;br /&gt;
&lt;br /&gt;
Running a cluster means built-in failover on the one hand, but might require some attention when it comes to the point of upgrading the services on all nodes in the cluster. This chapter gives an overview about general concepts and hints for silent updates of the cluster.&lt;br /&gt;
&lt;br /&gt;
== The Big Picture ==&lt;br /&gt;
&lt;br /&gt;
Updating an OX App Suite cluster is possible in several ways. The involved steps always include&lt;br /&gt;
&lt;br /&gt;
* Update the software by updating the packages through the distro's repository / software update tool&lt;br /&gt;
* Update the database schemas (so-called update tasks)&lt;br /&gt;
&lt;br /&gt;
There are some precautions required, though.&lt;br /&gt;
&lt;br /&gt;
=== Update Tasks Management ===&lt;br /&gt;
&lt;br /&gt;
It is a feature of the OX App Suite middleware to automatically start update tasks on a database schema when a user tries to login whose context lives on that schema. For installations beyond a certain size, if you just update the OX App Suite software without special handling of the update tasks, user logins will trigger an uncontrolled storm of update tasks on the databases, potentially leading to resource contention, unnecessary long update tasks runtimes, excessive load on the database server, maybe even service outages.&lt;br /&gt;
&lt;br /&gt;
So one key element of every update strategy is to avoid user logins on nodes which have already been updated to the new software version, while the database schemas are still on the old version. There are two fundamentally different approaches to this goal: use either a full downtime, or use a rolling update strategy.&lt;br /&gt;
&lt;br /&gt;
We describe the update strategy in more detail in the next section. Note that these are still high-level outlines of the actual procedure, which requires additional details with regards to Hazelcast, given further down below.&lt;br /&gt;
&lt;br /&gt;
==== Full downtime approach ====&lt;br /&gt;
&lt;br /&gt;
The full downtime approach is quite straightforward and involves&lt;br /&gt;
&lt;br /&gt;
* shutdown of all OX middleware nodes&lt;br /&gt;
* update the software on all OX App Suite (middleware and frontend) nodes&lt;br /&gt;
* execute the update tasks in a controlled way from one OX node&lt;br /&gt;
* restore the service&lt;br /&gt;
&lt;br /&gt;
This is the most general approach and always available, even if the rolling approach is not available due to Hazelcast constraints.&lt;br /&gt;
&lt;br /&gt;
==== Rolling strategy ====&lt;br /&gt;
&lt;br /&gt;
It is possible to execute the update tasks decoupled from the real update of the rest from the cluster, days or even weeks ahead of time, with the following approach:&lt;br /&gt;
&lt;br /&gt;
* If the load situation allows for it, take one node out of the loadbalancer (we call it the upgrade node). Otherwise, add a dedicated upgrade node to your cluster, identically configured to the other middleware nodes.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node&lt;br /&gt;
* update the software on the upgrade node&lt;br /&gt;
* execute all update tasks from the update node.&lt;br /&gt;
&lt;br /&gt;
In the last step, users from affected schemas will be logged out and denied service while the update tasks are running on their database schema. This is typically a short unavailability (some minutes) for a small part (1000...7000 depending on the installation) of the user base. This unavailability is of much lower impact than the unavailability of a full downtime, but you still might want to do this in the off-business hours.&lt;br /&gt;
&lt;br /&gt;
This way you end up with the production cluster running on the old version of OX App Suite, with the database already being upgraded to the next version. This is explicitly a valid and supported configuration. This approach offers the advantage that update tasks can be executed in advance, instead of doing them while the whole system is in a full maintenance downtime. Since update tasks can take some time, this is a considerable advantage.&lt;br /&gt;
&lt;br /&gt;
For the actual upgrade of the production cluster, the remaining steps are:&lt;br /&gt;
&lt;br /&gt;
* Upgrade and restart the OX App Suite software on one middleware node after another, one by one&lt;br /&gt;
* Upgrade the software on the OX App Suite frontend nodes (if these are separate nodes from the middleware nodes)&lt;br /&gt;
&lt;br /&gt;
Hazelcast will ensure that sessions from nodes which you restart are taken over by other nodes in the cluster, so ideally this step works without losing user sessions.&lt;br /&gt;
&lt;br /&gt;
For the rolling strategy to work as described, it is required that the old and new version of OX App Suite use compatible versions of the Hazelcast library. This is the case for most upgrades. However some upgrades must handle the situation that the new version of OX App Suite ships with a new version of Hazelcast incompatible to the version of Hazelcast shipped with the old version of OX App Suite. It will be stated in the release notes if this is the case for a given release. If so, then some additional steps are required during a rolling update to ensure session handling / invalidating during update tasks works properly. See below.&lt;br /&gt;
&lt;br /&gt;
== HOWTO / step-by-step instructions ==&lt;br /&gt;
&lt;br /&gt;
* Take backups of as much as possible (databases, OX config files, etc).&lt;br /&gt;
* Announce the maintenance to the users. The communication depends on which approach you chose: the full downtime approach will come with a full downtime for all users, while the rolling upgrade approach will result in some users will have a short loss of service while their schema upgrades.&lt;br /&gt;
&lt;br /&gt;
=== Full downtime approach ===&lt;br /&gt;
&lt;br /&gt;
* Initiate maintenance: Block HTTP sessions to the service. Put a reasonable maintenance page in place, probably some HTTP error 503 with a reasonable Retry-After header.&lt;br /&gt;
* Shutdown the service on all middleware nodes. Upgrade the software on all middleware and frontend nodes using the disto's package manager. See [[AppSuite:UpdatingOXPackages]] for details on how to do that. Don't forget the &amp;lt;code&amp;gt;touch-appsuite&amp;lt;/code&amp;gt; step if required (&amp;quot;If you update only UI plugins without simultaneously upgrading the core UI packages to a new version&amp;quot;).&lt;br /&gt;
* Start the &amp;lt;code&amp;gt;open-xchange&amp;lt;/code&amp;gt; service on one node&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that, in particular the [[UpdateTasks#How_to_see_all_schemas.3F|section]] about limited parallel execution.&lt;br /&gt;
* Start the &amp;lt;code&amp;gt;open-xchange&amp;lt;/code&amp;gt; services on the middleware nodes.&lt;br /&gt;
* Perform some crosschecks like&lt;br /&gt;
** all middleware nodes joined the Hazelcast cluster&lt;br /&gt;
** all OSGI bundles (which are expected to be running) are running&lt;br /&gt;
** WebUI login is possible&lt;br /&gt;
** Some central functionality tests like sending mails, accessing drive, etc&lt;br /&gt;
* Restore service: allow HTTP sessions, remove the maintenance page.&lt;br /&gt;
&lt;br /&gt;
=== Rolling Upgrade without breaking Hazelcast upgrade ===&lt;br /&gt;
&lt;br /&gt;
Remember: as stated above, this is viable only if the release notes for the new version do not state that there are breaking Hazelcast changes. For example, with v7.8.4 there were breaking Hazelcast changes and in the Release Notes it was stated as follows.&lt;br /&gt;
&lt;br /&gt;
https://software.open-xchange.com/products/appsuite/doc/Release_Notes_for_Release_7.8.4_2017-05-23.pdf&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Important - Please Note&lt;br /&gt;
&lt;br /&gt;
There is a major Hazelcast library update to OX App Suite v7.8.4. This means that when updating from an earlier backend version, due to the upgraded library, it is not possible to form a cluster of nodes that run previous version of Hazelcast (i.e. exiting volatile data in the cluster will be lost during the update). A consistent Hazelcast cluster is needed for cluster-wide cache invalidation. To circumvent problems with database update tasks that need to perform cache invalidation, please follow the steps described here: http://oxpedia.org/wiki/index.php?title=AppSuite:Running_a_cluster#Upgrades_of_the_Hazelcast_library. Please also note that session migration is not possible between versions. This usually affects all user sessions that are stored in a distributed map, and will require the users to re-login after the update. Running incompatible versions of Hazelcast within a cluster will result in logentries showing the conflicting node and version information.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you find you are upgrading to a version with breaking Hazelcast changes, please consult the next section [[#Rolling_Upgrade_with_breaking_Hazelcast_upgrade]].&lt;br /&gt;
&lt;br /&gt;
Pre-update:&lt;br /&gt;
&lt;br /&gt;
* Take one middleware node (the upgrade node) out of the HTTP traffic by adjusting the apache mod_proxy tables. We propose a combination of the balancer_manager to do this during runtime without restart, but also update the config files to prevent service restarts of apache to accidentally route sessions to the upgrade node.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node &lt;br /&gt;
* Update packages on the upgrade node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that. You might want to keep the load low on the DBs, to affect production operations as low as possible, and because with this decoupled update tasks approach there is no immediate time pressure. If you want to follow the [[UpdateTasks#How_to_see_all_schemas.3F|limited parallel]] approach, use a small, mild parallelity factor (e.g. 2 or maybe 4 if you know this by far does not saturate your DB platform).&lt;br /&gt;
&lt;br /&gt;
Real Update:&lt;br /&gt;
&lt;br /&gt;
* For one middleware cluster node after each nother:&lt;br /&gt;
** Update packages on that middleware node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
** Verify the node starts its bundles, joins the Hazelcast cluster, log files are clean, the node handles sessions&lt;br /&gt;
* For one frontend node after each other (if you've got separate frontend nodes):&lt;br /&gt;
** Update packages on that frontend node. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Finally, if required (&amp;quot;If you update only UI plugins without simultaneously upgrading the core UI packages to a new version&amp;quot;), execute &amp;lt;code&amp;gt;touch-appsuite&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;--timestamp&amp;lt;/code&amp;gt; argument as described on the page [[AppSuite:UpdatingOXPackages]]&lt;br /&gt;
* Perform final crosschecks like&lt;br /&gt;
** all middleware nodes joined the Hazelcast cluster&lt;br /&gt;
** all OSGI bundles (which are expected to be running) are running&lt;br /&gt;
** WebUI login is possible&lt;br /&gt;
** Some central functionality tests like sending mails, accessing drive, etc&lt;br /&gt;
&lt;br /&gt;
=== Rolling Upgrade with breaking Hazelcast upgrade ===&lt;br /&gt;
&lt;br /&gt;
Cf [[#Upgrades_of_the_Hazelcast_library]] below.&lt;br /&gt;
&lt;br /&gt;
In principle the steps given in the previous section apply. However the upgrade needs to get the special Hazelcast Upgrade Package installed (e.g. one from &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-76x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-780-782&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-783&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-784&amp;lt;/code&amp;gt;, ...) during execution of the update tasks.&lt;br /&gt;
&lt;br /&gt;
So the pre-update steps look like:&lt;br /&gt;
&lt;br /&gt;
* Take one middleware node (the upgrade node) out of the HTTP traffic by adjusting the apache mod_proxy tables. We propose a combination of the balancer_manager to do this during runtime without restart, but also update the config files to prevent service restarts of apache to accidentally route sessions to the upgrade node.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node &lt;br /&gt;
* Update packages on the upgrade node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Install the special Hazelcast Upgrade Package on the upgrade node (e.g. one from &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-76x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-780-782&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-783&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-784&amp;lt;/code&amp;gt;, ...). Restart the service again.&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that. You might want to keep the load low on the DBs, to affect production operations as low as possible, and because with this decoupled update tasks approach there is no immediate time pressure. If you want to follow the [[UpdateTasks#How_to_see_all_schemas.3F|limited parallel]] approach, use a small, mild parallelity factor (e.g. 2 or maybe 4 if you know this by far does not saturate your DB platform).&lt;br /&gt;
&lt;br /&gt;
Note: don't worry if you don't see the upgrade node joining the legacy cluster: the upgrade node will not join the legacy cluster / not be visisble there since the upgrade node will be a so-called &amp;quot;native client&amp;quot; to the legacy cluster, and it will be created on the fly (and subsequently disposed again) for propagating an event. So also on &amp;lt;code&amp;gt;netstat&amp;lt;/code&amp;gt; level the upgrade node will not have visible connections to the legacy cluster (unless for the very short timeframe when an actual even is sent). You can verify the functionality of that package by log lines like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; Successfully initialzed Hazelcast client: &amp;lt;client-id&amp;gt;&lt;br /&gt;
 Successfully got reference to cache event topic: cacheEvents-3&lt;br /&gt;
 Publishing legacy cache event: &amp;lt;cache-event&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Successfully published legacy cache event, shutting down client after 546ms...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the overly prudent it might be an idea to prepare a special test context with a test user living in its dedicated (test) schema, so you can test the functionality of this mechanis during upgrade first.&lt;br /&gt;
&lt;br /&gt;
After the DB update tasks you can remove the special upgrade package again from the upgrade node.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Real Upgrade&amp;quot; procedure then looks like [[#Rolling_Upgrade_without_breaking_Hazelcast_upgrade|above]].&lt;br /&gt;
&lt;br /&gt;
== Reference Documentation ==&lt;br /&gt;
&lt;br /&gt;
=== Limitations ===&lt;br /&gt;
&lt;br /&gt;
While in most cases a seamless, rolling upgrade of all nodes in the cluster is possible, there may be situations where nodes running a newer version of the Open-Xchange Server are not able to communicate with older nodes in the cluster, i.e. can't access distributed data or consume incompatible event notifications - especially, when the underlying Hazelcast library is part of the update, which does not support this scenario at the moment. In such cases, the release notes will contain corresponding information, so please have a look there before applying an update.&lt;br /&gt;
&lt;br /&gt;
Additionally, there may always be some kind of race conditions during an update, i.e. client requests that can't be completed successfully or internal events not being deliverd to all nodes in the cluster. That's why the following information should only serve as a best-practices guide to minimize the impact of upgrades to the user experience.&lt;br /&gt;
&lt;br /&gt;
=== Upgrading a single Node ===&lt;br /&gt;
&lt;br /&gt;
Upgrading all nodes in the cluster should usually be done sequentially, i.o.w. one node after the other. This means that during the upgrade of one node, the node is temporarily disconnected from the other nodes in the cluster, and will join the cluster again after the update is completed. From the backend perspective, this is as easy as stopping the open-xchange service. other nodes in the cluster will recognize the disconnected node and start to repartition the shared cluster data automatically. But wait a minute - doing so would potentially lead to the webserver not registering the node being stopped immediately, resulting in temporary errors for currently logged in users until they are routed to another machine in the cluster. That's why it's good practice to tell the webserver's load balancer that the node should no longer fulfill incoming requests. The Apache Balancer Manager is an excellent tool for this ([http://httpd.apache.org/docs/2.2/mod/mod_status.html module ''mod_status'']). Look at the screen shot. Every node can be put into a disabled mode. Further requests will the redirected to other nodes in the cluster:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:balancer_manager.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Afterwards, the open-xchange service on the disabled node can be stopped by executing:&lt;br /&gt;
&lt;br /&gt;
 $ /etc/init.d/open-xchange stop&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 $ service open-xchange stop&lt;br /&gt;
&lt;br /&gt;
Now, the node is effectively in maintenance mode and any updates can take place. One could now verify the changed cluster infrastructure by accessing the Hazelcast MBeans either via JMX or the ''showruntimestats -c'' commandline tool (see above for details). There, the shut down node should no longer appear in the 'Member' section (com.hazelcast:type=Member).&lt;br /&gt;
&lt;br /&gt;
When all upgrades are processed, the node open-xchange service can be started again by executing:&lt;br /&gt;
&lt;br /&gt;
 $ /etc/init.d/open-xchange start&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 $ service open-xchange start&lt;br /&gt;
&lt;br /&gt;
As stated above, depending on the chosen cluster discovery mechanism, it might take some time until the node joins the cluster again. When using static cluster discovery, it will join the existing cluster usually directly during serivce startup, i.o.w. before other depending OSGi services are started. Otherwise, there might also be situations where the node cannot join the cluster directly, for example when there were no mDNS advertisments for other nodes in the cluster received yet. Then, it can take some additional time until the node finally joins the cluster. During startup of the node, you can observe the JMX console or the output of ''showruntimestats -c'' (com.hazelcast:type=Member) of another node in the cluster to verify when the node has joined. &lt;br /&gt;
&lt;br /&gt;
After the node has joined, distributed data is re-partioned automatically, and the node is ready to server incoming requests again - so now the node can finally be enabled again in the load balancer configuration of the webserver. Afterwards, the next node in the cluster can be upgraded using the same procedure, until all nodes were processed.&lt;br /&gt;
&lt;br /&gt;
=== Upgrades of the Hazelcast library ===&lt;br /&gt;
&lt;br /&gt;
In case an upgrade includes a major update of the Hazelcast library, a newly upgraded node will usually not be able to connect to the nodes running the previous version. In this case, volatile cluster data is lost after all nodes in the cluster have been updated, including sessions held in the distributed session storage. As outlined above, the release notes will contain a corresponding warning in such cases.&lt;br /&gt;
&lt;br /&gt;
Besides upgraded nodes not being able to access distributed data of the legacy cluster, this also affects new data not being available in the legacy cluster, which may cause troubles if the updated backend version needs to perform database update tasks. Database update tasks usually operate in a &amp;quot;blocking&amp;quot; way and all contexts associated with the schema being upgraded are disabled temporarily. Since context data itself is being held in caches on potentially each node in the cluster, the affected cache entries are invalidated during the database update. And, since cluster-wide cache invalidations again utilize Hazelcast functionality ([[#Remote Cache Invalidation]]), such invalidations normally won't be propagated to nodes running a previous version of the Hazelcast library.&lt;br /&gt;
&lt;br /&gt;
To work around this specific scenario where an incompatible upgrade of the Hazelcast library needs to be performed along with blocking database update tasks, starting with v7.8.0, a supplementary package is available that explicitly enables the context cache invalidation of nodes running the previous Hazelcast library. This package follows the naming scheme ''open-xchange-cluster-upgrade-from-XXX'' (where XXX representing the version of the legacy version of the Open-Xchange server), and is available in the repositories for the updated server packages. This package should only be installed on the first node of the cluster that is going to be upgraded to the new version, and can be deactivated once the database upgrade tasks were executed successfully. &lt;br /&gt;
&lt;br /&gt;
Once installed, a legacy cluster is discovered based on the available information in the ''hazelcast.properties'' configuration file in case cluster discovery is set to ''static''. If ''multicast'' is used, there's an alternative option to configure at least one of the addresses of the legacy cluster via ''com.openexchange.hazelcast.network.client.nodes''.&lt;br /&gt;
&lt;br /&gt;
As an example, along with the server v7.8.0, a new package named ''open-xchange-cluster-upgrade-from-76x'' can be installed that aids in invalidating cluster server nodes running v7.6.x (which includes the Hazelcast library in version 3.2.4). Using this package, the recommended steps to update an OX cluster from version 7.6.x to version 7.8.0 would be:&lt;br /&gt;
# Pick a node from your cluster that you want to use for executing the database update tasks shipped with the new release&lt;br /&gt;
# Disable this node for incoming HTTP requests in your webserver configuration as described at [[#Upgrading a single Node]]&lt;br /&gt;
# Update the OX packages on this node, additionally install the package ''open-xchange-cluster-upgrade-from-76x''&lt;br /&gt;
# Restart the open-xchange services on this node&lt;br /&gt;
# Trigger the update task executions using the ''runUpdate'' commandline utitlty as described at [[UpdateTasks]]&lt;br /&gt;
# Once they are finished, uninstall the package ''open-xchange-cluster-upgrade-from-76x'' again&lt;br /&gt;
# Restart the open-xchange services on this node&lt;br /&gt;
# Re-enable the node for incoming HTTP requests in your webserver configuration as described at [[#Upgrading a single Node]]&lt;br /&gt;
# Upgrade all other nodes in the cluster as described at [[#Upgrading a single Node]]&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.0 through v7.8.2 (incl.) to v7.8.3 using the package named ''open-xchange-cluster-upgrade-from-780-782'', since v7.8.0 through v7.8.2 (incl.) utilize Hazelcast v3.5.x, while v7.8.3 uses Hazelcast v3.6.4&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.3 to v7.8.4 using the package named ''open-xchange-cluster-upgrade-from-783'', since v7.8.3 utilizes Hazelcast v3.7.1&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.4 to v7.10.0 using the package named ''open-xchange-cluster-upgrade-from-784'', since v7.8.4 utilizes Hazelcast v3.8.1&lt;br /&gt;
&lt;br /&gt;
'''Operations Note:''' The upgraded node will be added as so-called [http://docs.hazelcast.org/docs/2.3/manual/html/ch15.html Native Client] to the legacy Hazelcast Cluster.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Native Client enables you to do all Hazelcast operations without being a member of the cluster.&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
However Native client is not member and relies on one of the cluster members.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means, the upgraded node will not be visible in the members list of the legacy Hazelcast cluster (&amp;lt;code&amp;gt;showruntimestats -c&amp;lt;/code&amp;gt;). Furthermore, the native client will created and destructed on single context events, with the effect that connections will only be visible in the very moment of such an event. This means effectively that verification of the invalidation mechanis is only possible by actually executing the &amp;lt;code&amp;gt;runupdate&amp;lt;/code&amp;gt; CLT. This should produce log lines like&lt;br /&gt;
&lt;br /&gt;
 Successfully initialzed Hazelcast client: &amp;lt;client-id&amp;gt;&lt;br /&gt;
 Successfully got reference to cache event topic: cacheEvents-3&lt;br /&gt;
 Publishing legacy cache event: &amp;lt;cache-event&amp;gt;&lt;br /&gt;
 Successfully published legacy cache event, shutting down client after 546ms...&lt;br /&gt;
&lt;br /&gt;
Most importantly, you should be able to observe correct functionality (users of affected contexts being logged out). It may be handy to prepare a dedicated schema with just test contexts inside. (How to create this is out of scope here, but hint: use &amp;lt;code&amp;gt;createschema&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;createcontext --schema-name&amp;lt;/code&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
=== Other Considerations ===&lt;br /&gt;
&lt;br /&gt;
* It's always recommended to only upgrade one node after the other, always ensuring that the cluster has formed correctly between each shutdown/startup of a node.&lt;br /&gt;
* Do not stop a node while running the runUpdate script or the associated update task.&lt;br /&gt;
* During the time of such a rolling upgrade of all nodes, we have effectively heterogeneous software versions in the cluster, which potentially might lead to temporary inconsistencies. Therefore, all nodes in the cluster should be updated in one cycle (but still one after the other).&lt;br /&gt;
* Following the above guideline, it's also possible to add or remove nodes dynamically to the cluster, not only when disconnecting a node temporary for updates.&lt;br /&gt;
* In case of trouble, i.e. a node refuses to join the cluster again after restart, consult the logfiles first for any hints about what is causing the problem - both on the disconnected node, and also on other nodes in the network&lt;br /&gt;
* If there are general incompatibilities between two revisions of the Open-Xchange Server that prevent an operation in a cluster (release notes), it's recommended to choose another name for the cluster in ''cluster.properties'' for the nodes with the new version. This will temporary lead to two separate clusters during the rolling upgrade, and finally the old cluster being shut down completely after the last node was updated to the new version. While distributed data can't be migrated from one server version to another in this scenario due to incompatibilities, the uptime of the system itself is not affected, since the nodes in the new cluster are able to serve new incoming requests directly.&lt;br /&gt;
* When updating only UI plugins without also updating to a new version of the core UI, you also need to perform the additional step from [[AppSuite:UpdatingOXPackages#Updating_UI_plugins|Updating UI plugins]].&lt;br /&gt;
&lt;br /&gt;
[[Category: AppSuite]] [[Category: Administration]] [[Category: Cluster]]&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Running_a_cluster&amp;diff=23788</id>
		<title>AppSuite:Running a cluster</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Running_a_cluster&amp;diff=23788"/>
		<updated>2017-12-13T08:10:24Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Full downtime approach */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Running a cluster&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Concepts =&lt;br /&gt;
&lt;br /&gt;
For inter-OX-communication over the network, multiple Open-Xchange servers can form a cluster. This brings different advantages regarding distribution and caching of volatile data, load balancing, scalability, fail-safety and robustness. Additionally, it provides the infrastructure for upcoming features of the Open-Xchange server. &lt;br /&gt;
The clustering capabilities of the Open-Xchange server are mainly built up on [http://hazelcast.com Hazelcast], an open source clustering and highly scalable data distribution platform for Java. The following article provides an overview about the current featureset and configuration options.&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
== Synchronized system clock times ==&lt;br /&gt;
It is crucial that all involved members in a cluster do have their system clock times in sync with each other; e.g. by using an NTP service.&lt;br /&gt;
&lt;br /&gt;
== HTTP routing ==&lt;br /&gt;
An OX cluster is always part of a larger picture. Usually there is front level loadbalancer as central HTTPS entry point to the platform. This loadbalancer optionally performs HTTPS termination and forwards HTTP(S) requests to webservers (the usual and only supported choice as of now is Apache). These webservers are performing HTTPS termination (if this is not happening on the loadbalancer) and serve static content, and (which is what is relevant for our discussion here) they forward dynamic requests to the OX backends.&lt;br /&gt;
&lt;br /&gt;
A central requirement for the interaction of these components (loadbalancer, webservers, OX nodes) is that we have session stability based on the JSESSIONID cookie / jsessionid path component suffix. This means that our application sets a cookie named JSESSIONID which has a value like &amp;lt;large decimal number&amp;gt;.&amp;lt;route identifier&amp;gt;, e.g. &amp;quot;5661584529655240315.OX1&amp;quot;. The route identifier here (&amp;quot;OX1&amp;quot; in this example) is taken by the OX node from a configuration setting from a config file and is specific to one OX node. HTTP routing must happen such that HTTP requests with a cookie with such a suffix always end up the corresponding OX node. There are furthermore specific cirumstances when passing this information via cookie is not possible. Then the JSESSIONID is transferred in a path component as &amp;quot;jsessionid=...&amp;quot; in the HTTP request. The routing mechanism needs to take that into account also.&lt;br /&gt;
&lt;br /&gt;
There are mainly two options to implement this. If the Apache processes are running co-located on the same machines running the OX groupware processes, it is often desired to have the front level loadbalancer perform HTTP routing to the correct machines. If dedicated Apache nodes are employed, is is usually sufficient to have the front-level loadbalancer do HTTP routing to the Apache nodes in a round-robin fashion and perform routing to the correct OX nodes in the Apache nodes.&lt;br /&gt;
&lt;br /&gt;
We provide sample configuration files to configure Apache (with mod_proxy_http) to perform HTTP routing correctly in our guides on OXpedia, e.g. [[AppSuite:Main_Page_AppSuite#quickinstall]]. Central elements are the directives &amp;quot;ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&amp;quot; in conjunction with the &amp;quot;route=OX1&amp;quot; parameters to the BalancerMember lines in the Proxy definition. This is valid for Apache 2.2 as of Sep-2014.&lt;br /&gt;
&lt;br /&gt;
How to configure a front level loadbalancer to perform HTTP equivalent HTTP routing is dependent on the specific loadbalancer implementation. If Apache is used as front level loadbalancer, the same configuration as discussed in the previous section can be employed. As of time of writing this text (Sep 2014), the alternative choices are thin. F5 BigIP is reported to be able to implement &amp;quot;jsessionid based persistence using iRules&amp;quot;. nginx has the functionality in their commercial &amp;quot;nginx plus&amp;quot; product. (Both of these options have not been tested by OX.) Other loadbalancers with this functionality are not known to us.&lt;br /&gt;
&lt;br /&gt;
If the front level loadbalancer is not capable of performing correct HTTP routing, is is required to configure correct HTTP routing on Apache level, even if Apache runs co-located on the OX nodes and thus cross-routing happens.&lt;br /&gt;
&lt;br /&gt;
There are several reasons why we require session stability in exactly this way. We require session stabilty for horizontal scale-out; while we support transparent resuming / migration of user sessions in the OX cluster without need for users to re-authenticate, sessions wandering around randomly will consume a fixed amount resources corresponding to a running session on each OX node in the cluster, while a session sticky to one OX node will consume this fixed amount of resources only on one OX node. Furthermore there are mechanisms in OX like TokenLogin which work only of all requests beloning to one sequence get routed to the same OX node even if they stem from different machines with different IPs. Only the JSESSIONID (which in this case is transferred as jsessionid path component, as cookies do not work during a 302 redirect, which is part of this sequence) carries the required information where the request must be routed to.&lt;br /&gt;
&lt;br /&gt;
Usual &amp;quot;routing based on cookie hash&amp;quot; is not sufficient here since it disregards the information which machine originally issued the cookie. It only ensures that the session will be sticky to any target, which statistically will not be the same machine that issued the cookie. OX will then set a new JSESSIONID cookie, assuming the session had been migrated. The loadbalancer will then route the session to a different target, as the hash of the cookie will differ. This procedure then happens iteratively until by chance the routing based on cookie hash will route the session to the correct target. By then, a lot of resources will have been wasted, by creating full (short-term) sessions on all OX nodes. Furthermore, processes like TokenLogin will not work this way.&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
&lt;br /&gt;
All settings regarding cluster setup are located in the configuration file ''hazelcast.properties''. The former used additional files ''cluster.properties'', ''mdns.properties'' and ''static-cluster-discovery.properties'' are no longer needed. The following gives an overview about the most important settings - please refer to the inline documentation of the configuration file for more advanced options.&lt;br /&gt;
&lt;br /&gt;
Note: The configuration guide targets v7.4.0 of the OX server (and above). For older versions, please consult the history of this page. A full list of Hazelcast-related properties is available at https://documentation.open-xchange.com/components/middleware/config/7.8.4/#mode=features&amp;amp;feature=Hazelcast .&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
To restrict access to the cluster and to separate the cluster from others in the local network, a name and password needs to be defined. Only backend nodes having the same values for those properties are able to join and form a cluster. &lt;br /&gt;
&lt;br /&gt;
 # Configures the name of the cluster. Only nodes using the same group name &lt;br /&gt;
 # will join each other and form the cluster. Required if &lt;br /&gt;
 # &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is not &amp;quot;empty&amp;quot; (see below).&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&lt;br /&gt;
 &lt;br /&gt;
 # The password used when joining the cluster. Defaults to &amp;quot;wtV6$VQk8#+3ds!a&amp;quot;. &lt;br /&gt;
 # Please change this value, and ensure it's equal on all nodes in the cluster.&lt;br /&gt;
 com.openexchange.hazelcast.group.password=wtV6$VQk8#+3ds!a&lt;br /&gt;
&lt;br /&gt;
== Network ==&lt;br /&gt;
&lt;br /&gt;
It's required to define the network interface that is used for cluster communication via ''com.openexchange.hazelcast.network.interfaces''. By default, the interface is restricted to the local loopback address only. To allow the same configuration amongst all nodes in the cluster, it's recommended to define the value using a wildcard matching the IP addresses of all nodes participating in the cluster, e.g. ''192.168.0.*''&lt;br /&gt;
&lt;br /&gt;
 # Comma-separated list of interface addresses hazelcast should use. Wildcards &lt;br /&gt;
 # (*) and ranges (-) can be used. Leave blank to listen on all interfaces&lt;br /&gt;
 # Especially in server environments with multiple network interfaces, it's &lt;br /&gt;
 # recommended to specify the IP-address of the network interface to bind to &lt;br /&gt;
 # explicitly. Defaults to &amp;quot;127.0.0.1&amp;quot; (local loopback only), needs to be &lt;br /&gt;
 # adjusted when building a cluster of multiple backend nodes.&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=127.0.0.1&lt;br /&gt;
&lt;br /&gt;
To form a cluster of multiple OX server nodes, different discovery mechanisms can be used. The discovery mechanism is specified via the property ''com.openexchange.hazelcast.network.join'':&lt;br /&gt;
&lt;br /&gt;
 # Specifies which mechanism is used to discover other backend nodes in the &lt;br /&gt;
 # cluster. Possible values are &amp;quot;empty&amp;quot; (no discovery for single-node setups),&lt;br /&gt;
 # &amp;quot;static&amp;quot; (fixed set of cluster member nodes) or &amp;quot;multicast&amp;quot; (automatic &lt;br /&gt;
 # discovery of other nodes via multicast). Defaults to &amp;quot;empty&amp;quot;. Depending on &lt;br /&gt;
 # the specified value, further configuration might be needed, see &amp;quot;Networking&amp;quot;&lt;br /&gt;
 # section below. &lt;br /&gt;
 com.openexchange.hazelcast.network.join=empty&lt;br /&gt;
&lt;br /&gt;
Generally, it's advised to use the same network join mechanism for all nodes in the cluster, and, in most cases, it's strongly recommended to use a ''static'' network join configuration. This will allow the nodes to join the cluster directly upon startup. With a ''multicast'' based setup, nodes will merge to an existing cluster possibly at some later time, thus not being able to access the distributed data until they've joined.&lt;br /&gt;
&lt;br /&gt;
Depending on the network join setting, further configuration may be necessary, as decribed in the following paragraphs.&lt;br /&gt;
&lt;br /&gt;
=== empty ===&lt;br /&gt;
&lt;br /&gt;
When using the default value ''empty'', no other nodes are discovered in the cluster. This value is suitable for single-node installations. Note that other nodes that are configured to use other network join mechanisms may be still able to still to connect to this node, e.g. using a ''static'' network join, having the IP address of this host in the list of potential cluster members (see below).&lt;br /&gt;
&lt;br /&gt;
=== static ===&lt;br /&gt;
&lt;br /&gt;
The most common setting for ''com.openexchange.hazelcast.network.join'' is ''static''. A static cluster discovery uses a fixed list of IP addresses of the nodes in the cluster. During startup and after a specific interval, the underlying Hazelcast library probes for not yet joined nodes from this list and adds them to the cluster automatically. The address list is configured via ''com.openexchange.hazelcast.network.join.static.nodes'':&lt;br /&gt;
&lt;br /&gt;
 # Configures a comma-separated list of IP addresses / hostnames of possible &lt;br /&gt;
 # nodes in the cluster, e.g. &amp;quot;10.20.30.12, 10.20.30.13:5701, 192.178.168.110&amp;quot;.&lt;br /&gt;
 # Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set to &amp;quot;static&amp;quot;. &lt;br /&gt;
 # It doesn't hurt if the address of the local host appears in the list, so &lt;br /&gt;
 # that it's still possible to use the same list throughout all nodes in the &lt;br /&gt;
 # cluster.&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=&lt;br /&gt;
&lt;br /&gt;
For a fixed set of backend nodes, it's recommended to simply include the IP addresses of all nodes in the list, and use the same configuration for each node. However, it's only required to add the address of at least one other node in the cluster to allow the node to join the cluster. Also, when adding a new node to the cluster and this list is extended accordingly, existing nodes don't need to be shut down to recognize the new node, as long as the new node's address list contains at least one of the already running nodes. &lt;br /&gt;
&lt;br /&gt;
=== multicast ===&lt;br /&gt;
&lt;br /&gt;
For highly dynamic setups where nodes are added and removed from the cluster quite often and/or the host's IP addresses are not fixed, it's also possible to configure the network join via multicast. During startup and after a specific interval, the backend nodes initiate the multicast join process automatically, and discovered nodes form or join the cluster afterwards. The multicast group and port can be configured as follows:&lt;br /&gt;
&lt;br /&gt;
 # Configures the multicast address used to discover other nodes in the cluster&lt;br /&gt;
 # dynamically. Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set &lt;br /&gt;
 # to &amp;quot;multicast&amp;quot;. If the nodes reside in different subnets, please ensure that &lt;br /&gt;
 # multicast is enabled between the subnets. Defaults to &amp;quot;224.2.2.3&amp;quot;. &lt;br /&gt;
 com.openexchange.hazelcast.network.join.multicast.group=224.2.2.3&lt;br /&gt;
 &lt;br /&gt;
 # Configures the multicast port used to discover other nodes in the cluster&lt;br /&gt;
 # dynamically. Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set &lt;br /&gt;
 # to &amp;quot;multicast&amp;quot;. Defaults to &amp;quot;54327&amp;quot;. &lt;br /&gt;
 com.openexchange.hazelcast.network.join.multicast.port=54327&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
&lt;br /&gt;
The following example shows how a simple cluster named ''MyCluster'' consisting of 4 backend nodes can be configured using ''static'' cluster discovery. The node's IP addresses are 10.0.0.15, 10.0.0.16, 10.0.0.17 and 10.0.0.18. Note that the same ''hazelcast.properties'' is used by all nodes.&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.group.name=MyCluster&lt;br /&gt;
 com.openexchange.hazelcast.group.password=secret&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=10.0.0.15,10.0.0.16,10.0.0.17,10.0.0.18&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=10.0.0.*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Advanced Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== Lite Members (available since v7.8.4) ===&lt;br /&gt;
&lt;br /&gt;
Lite members in a Hazelcast cluster are members that do not hold any data partitions, i.e. all read- and write operations to distributed maps are delegated to non-lite (&amp;quot;full&amp;quot;) members. Apart from not having data partitions, lite members participate in the same way as other members: they can register listeners for distributed topics (e.g. cache invalidation events) or can be addressed for task execution (e.g. during realtime communication). &lt;br /&gt;
&lt;br /&gt;
Similar to using a custom partitioning scheme, separating the nodes of a large cluster into few &amp;quot;full&amp;quot; members and many &amp;quot;lite&amp;quot; members helps to minimize the impact of JVM activities from a single node (mainly the garbage collector) on the whole cluster communication. Additionally, when starting or stopping lite members, no repartitioning of the distributed cluster data needs to be performed, which significantly decreases the node's startup- and shutdown time and reduces the necessary network communication to a minimum. &lt;br /&gt;
&lt;br /&gt;
In medium or larger sized clusters, it is sufficient to have roughly 10 to 20 percent of the nodes configured as &amp;quot;full&amp;quot; members, while all other ones can be started as &amp;quot;lite&amp;quot; member nodes. Additionally, please note that the configured backup count in the map configurations should always be smaller than the total number of &amp;quot;full&amp;quot; members, otherwise, there may be problems if one of those data nodes is shut down temporarily for maintenance. So, the minimum number of &amp;quot;full&amp;quot; members is implicitly bound to the sum of a map's ''backupCount'' and ''asyncBackupCount'' properties, plus ''1'' for the original data partition. &lt;br /&gt;
&lt;br /&gt;
The configured &amp;quot;full&amp;quot; members should preferrably not be used to serve client requests (by not adding them as endpoint in the loadbalancer), to ensure they are always responsive. Also, shutdown and startups of those &amp;quot;full&amp;quot; members should be reduced to a minimum to avoid repartitioning operations. &lt;br /&gt;
&lt;br /&gt;
More general information regarding lite members is available at http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#enabling-lite-members .&lt;br /&gt;
&lt;br /&gt;
To configure a node as &amp;quot;lite&amp;quot; member, the following configuration should be applied in the node's ''hazelcast.properties'' file:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.liteMember=true&lt;br /&gt;
&lt;br /&gt;
It's also recommended to use a &amp;quot;static&amp;quot; cluster discovery for the network join, and list all &amp;quot;full&amp;quot; member nodes here, so that join requests are handled by those nodes, too (and not the other nodes that are potentially prone to garbage collection delays. &lt;br /&gt;
&lt;br /&gt;
=== Custom Partitioning ===&lt;br /&gt;
&lt;br /&gt;
Note: Starting with v7.8.4, &amp;quot;Lite Members&amp;quot; should be used in favor of applying a custom partitioning scheme.&lt;br /&gt;
&lt;br /&gt;
While originally being designed to separate the nodes holding distributed data into different risk groups for increased fail safety, a custom partitioning strategy may also be used to distinguish between nodes holding distributed data from those who should not. &lt;br /&gt;
&lt;br /&gt;
This approach of custom partitioning may be used in a OX cluster, where usually different backend nodes serve different purposes. A common scenario is that there are nodes handling requests from the web interfaces, and others being responsible for USM/EAS traffic. Due to their nature of processing large chunks of synchronization data in memory, the USM/EAS nodes may encounter small delays when the Java garbage collector kicks in and suspends the Java Virtual Machine. Since those delays may also have an influence on hazelcast-based communication in the cluster, the idea is to instruct hazelcast to not store distributed data on that nodes. This is where a custom partitioning scheme comes into play.&lt;br /&gt;
&lt;br /&gt;
To setup a custom partitioning scheme in the cluster, an additional ''hazelcast.xml'' configuration file is used, which should be placed into the ''hazelcast'' subdirectory of the OX configuration folder, usually at ''/opt/openexchange/etc/hazelcast''. Please note that it's vital that each node in the cluster is configured equally here, so the same ''hazelcast.xml'' file should be copied to each server. The configuration read from there is used as basis for all further settings that are taken from the ordinary ''hazelcast.properties'' config file. &lt;br /&gt;
&lt;br /&gt;
To setup a custom partitioning scheme, the partition groups must be defined in the ''hazelcast.xml'' file. See the following file for an example configuration, where the three nodes ''10.10.10.60'', ''10.10.10.61'' and ''10.10.10.62'' are defined to form an own partitioning group each. Doing so, all distributed data will be stored at one of those nodes physically, while the corresponding backup data (if configured) at one of the other two nodes. All other nodes in the cluster will not be used to store distributed data, but will still be &amp;quot;full&amp;quot; hazelcast members, which is necessary for other cluster-wide operations the OX backends use. &lt;br /&gt;
&lt;br /&gt;
Please note that the configured backup count in the map configurations should be smaller than the number of nodes here, otherwise, there may be problems if one of those data nodes is shut down temporarily for maintenance. So, the minimum number of nodes to define in the partition group sections is implicitly bound to the sum of a map's ''backupCount'' and ''asyncBackupCount'' properties, plus ''1'' for the original data partition. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
 &amp;lt;!--&lt;br /&gt;
   ~ Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.&lt;br /&gt;
   ~&lt;br /&gt;
   ~ Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
   ~ you may not use this file except in compliance with the License.&lt;br /&gt;
   ~ You may obtain a copy of the License at&lt;br /&gt;
   ~&lt;br /&gt;
   ~ http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
   ~&lt;br /&gt;
   ~ Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
   ~ distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
   ~ See the License for the specific language governing permissions and&lt;br /&gt;
   ~ limitations under the License.&lt;br /&gt;
   --&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;hazelcast xsi:schemaLocation=&amp;quot;http://www.hazelcast.com/schema/config hazelcast-config-3.1.xsd&amp;quot;&lt;br /&gt;
            xmlns=&amp;quot;http://www.hazelcast.com/schema/config&amp;quot;&lt;br /&gt;
            xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;partition-group enabled=&amp;quot;true&amp;quot; group-type=&amp;quot;CUSTOM&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.60&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.61&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.62&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
     &amp;lt;/partition-group&amp;gt;&lt;br /&gt;
 &amp;lt;/hazelcast&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More general information regarding custom partioning is available at http://hazelcast.org/docs/latest/manual/html/partitiongroupconfig.html . &lt;br /&gt;
&lt;br /&gt;
It's also recommended to use a &amp;quot;static&amp;quot; cluster discovery for the network join, and list same the nodes that are also configured in the parition groups here, so that join requests are handled by those nodes, too (and not the other nodes that are potentially prone to garbage collection delays. &lt;br /&gt;
&lt;br /&gt;
After configuring a custom partitioning scheme, the data distribution may be verified, e.g. by inspecting the MBeans of the distributed maps via JMX.&lt;br /&gt;
&lt;br /&gt;
= Features =&lt;br /&gt;
&lt;br /&gt;
The following list gives an overview about different features that were implemented using the new cluster capabilities.&lt;br /&gt;
&lt;br /&gt;
== Distributed Session Storage ==&lt;br /&gt;
&lt;br /&gt;
Previously, when an Open-Xchange server was shutdown for maintenance, all user sessions that were bound to that machine were lost, i.e. the users needed to login again. With the distributed session storage, all sessions are backed by a distributed map in the cluster, so that they are no longer bound to a specific node in the cluster. When a node is shut down, the session data is still available in the cluster and can be accessed from the remaining nodes. The load-balancing techniques of the webserver then seamlessly routes the user session to another node, with no ''session expired'' errors. The distributed session storage comes with the package ''open-xchange-sessionstorage-hazelcast''. It's recommended to install this optional package in all clustered environments with multiple groupware server nodes.&lt;br /&gt;
&lt;br /&gt;
'''Notes:''' &lt;br /&gt;
* While there's some kind of built-in session distribution among the nodes in the cluster, this should not be seen as a replacement for session-stickiness between the loadbalancer and groupware nodes, i.e. one should still configure the webserver to use sticky sessions for performance reasons.&lt;br /&gt;
* The distributed session storage is still an in-memory storage. While the session data is distributed and backed up on multiple nodes in the cluster, shutting down multiple or all nodes at the same time will lead to loss of the the distributed data. To avoid such data loss when shutting down a node, please follow the guidelines at [[ Updating_a_Cluster ]].&lt;br /&gt;
&lt;br /&gt;
Depending on the cluster infrastructure, different backup-count configuration options might be set for the distributed session storage in the map configuration file ''sessions.properties'' in the ''hazelcast'' subdirectory:&lt;br /&gt;
&lt;br /&gt;
   com.openexchange.hazelcast.configuration.map.backupCount=1&lt;br /&gt;
&lt;br /&gt;
The ''backupcount'' property configures the number of nodes with synchronized backups. Synchronized backups block operations until backups are successfully copied and acknowledgements are received. If 1 is set as the backup-count for example, then all entries of the map will be copied to another JVM for fail-safety. 0 means no backup. Any integer between 0 and 6. Default is 1, setting bigger than 6 has no effect.&lt;br /&gt;
&lt;br /&gt;
   com.openexchange.hazelcast.configuration.map.asyncBackupCount=0&lt;br /&gt;
&lt;br /&gt;
The ''asyncbackup'' property configures the number of nodes with async backups. Async backups do not block operations and do not require acknowledgements. 0 means no backup. Any integer between 0 and 6. Default is 0, setting bigger than 6 has no effect.&lt;br /&gt;
&lt;br /&gt;
Since session data is backed up by default continuously by multiple nodes in the cluster, the steps described in [[ Session_Migration ]] to trigger session migration to other nodes explicitly is obsolete and no longer needed with the distributed session storage.&lt;br /&gt;
&lt;br /&gt;
Normally, sessions in the distributed storages are not evicted automatically, but are only removed when they're also removed from the session handler, either due to a logout operation or when exceeding the long-term session lifetime as configured by ''com.openexchange.sessiond.sessionLongLifeTime'' in ''sessiond.properties''. Under certain circumstances, i.e. the session is no longer accessed by the client and the OX node hosting the session in it's long-life container being shutdown, the remove operation from the distributed storage might not be triggered. Therefore, additionaly a maximum idle time of map-entries can be configured for the distributed sessions map via &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.configuration.map.maxIdleSeconds=640000&lt;br /&gt;
&lt;br /&gt;
To avoid unnecessary eviction, the value should be higher than the configured ''com.openexchange.sessiond.sessionLongLifeTime'' in ''sessiond.properties''.&lt;br /&gt;
&lt;br /&gt;
== Remote Cache Invalidation ==&lt;br /&gt;
&lt;br /&gt;
For faster access, groupware data is held in different caches by the server. Formerly, the caches utilized the TCP Lateral Auxiliary Cache plug in (LTCP) for the underlying JCS caches to broadcast updates and removals to caches on other OX nodes in the cluster. This could potentially lead to problems when remote invalidation was not working reliably due to network discovery problems. As an alternative, remote cache invalidation can also be performed using reliable publish/subscribe events built up on Hazelcast topics. This can be configured in the ''cache.properties'' configuration file, where the 'eventInvalidation' property can either be set to 'false' for the legacy behavior or 'true' for the new mechanism:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.caching.jcs.eventInvalidation=true&lt;br /&gt;
&lt;br /&gt;
All nodes participating in the cluster should be configured equally.&lt;br /&gt;
&lt;br /&gt;
Internally, if ''com.openexchange.caching.jcs.eventInvalidation'' is set to ''true'', LTCP is disabled in JCS caches. Instead, an internal mechanism based on distributed Hazelcast event topics is used to invalidate data throughout all nodes in the cluster after local update- and remove-operations. Put-operations aren't propagated (and haven't been with LTCP either), since all data put into caches can be locally loaded/evaluated at each node from the persistent storage layer.&lt;br /&gt;
&lt;br /&gt;
Using Hazelcast-based cache invalidation also makes further configuration of the JCS auxiliaries obsolete in the ''cache.ccf'' configuration file. In that case, all ''jcs.auxiliary.LTCP.*'' configuration settings are virtually ignored. However, it's still required to mark caches that require cluster-wide invalidation via ''jcs.region.&amp;lt;cache_name&amp;gt;=LTCP'', just as before. So basically, when using the new default setting ''com.openexchange.caching.jcs.eventInvalidation=true'', it's recommended to just use the stock ''cache.ccf'' file, since no further LTCP configuration is required.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
= Adminstration / Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
== Hazelcast Configuration ==&lt;br /&gt;
&lt;br /&gt;
The underlying Hazelcast library can be configured using the file ''hazelcast.properties''.&lt;br /&gt;
&lt;br /&gt;
'''Important''':&amp;lt;br&amp;gt;&lt;br /&gt;
By default property ''com.openexchange.hazelcast.network.interfaces'' is set to ''127.0.0.1''; meaning Hazelcast listens only to loop-back device. To build a cluster among remote nodes the appropriate network interface needs to be configured there. Leaving that property empty lets Hazelcast listen to all available network interfaces.&lt;br /&gt;
&lt;br /&gt;
The Hazelcast JMX MBean can be enabled or disabled with the property ''com.openexchange.hazelcast.jmx''. The properties ''com.openexchange.hazelcast.mergeFirstRunDelay'' and ''com.openexchange.hazelcast.mergeRunDelay'' control the run intervals of the so-called ''Split Brain Handler'' of Hazelcast that initiates the cluster join process when a new node is started. More details can be found at http://www.hazelcast.com/docs/2.5/manual/single_html/#NetworkPartitioning. &lt;br /&gt;
&lt;br /&gt;
The port ranges used by Hazelcast for incoming and outgoing connections can be controlled via the configuration parameters ''com.openexchange.hazelcast.networkConfig.port'', ''com.openexchange.hazelcast.networkConfig.portAutoIncrement'' and ''com.openexchange.hazelcast.networkConfig.outboundPortDefinitions''.&lt;br /&gt;
&lt;br /&gt;
== Commandline Tool ==&lt;br /&gt;
&lt;br /&gt;
To print out statistics about the cluster and the distributed data, the ''showruntimestats'' commandline tool can be executed witht the ''clusterstats'' ('c') argument. This provides an overview about the runtime cluster configuration of the node, other members in the cluster and distributed data structures.&lt;br /&gt;
&lt;br /&gt;
== JMX ==&lt;br /&gt;
&lt;br /&gt;
In the Open-Xchange server Java process, the MBean ''com.hazelcast'' can be used to monitor and manage different aspects of the underlying Hazelcast cluster. The ''com.hazelcast'' MBean provides detailed information about the cluster configuration and distributed data structures.&lt;br /&gt;
&lt;br /&gt;
== Hazelcast Errors ==&lt;br /&gt;
&lt;br /&gt;
When experiencing hazelcast related errors in the logfiles, most likely different versions of the packages are installed, leading to different message formats that can't be understood by nodes using another version. Examples for such errors are exceptions in hazelcast components regarding (de)serialization or other message processing.&lt;br /&gt;
This may happen when performing a consecutive update of all nodes in the cluster, where temporarily nodes with a heterogeneous setup try to communicate with each other. If the errors don't disappear after all nodes in the cluster have been update to the same package versions, it might be necessary to shutdown the cluster completely, so that all distributed data is cleared.&lt;br /&gt;
&lt;br /&gt;
== Cluster Discovery Errors ==&lt;br /&gt;
&lt;br /&gt;
* If the started OX nodes don't form a cluster, please double-check your configuration in ''hazelcast.properties''&lt;br /&gt;
* It's important to have the same cluster name defined in ''hazelcast.properties'' throughout all nodes in the cluster&lt;br /&gt;
* Especially when using multicast cluster discovery, it might take some time until the cluster is formed&lt;br /&gt;
* When using ''static'' cluster discovery, at least one other node in the cluster has to be configured in ''com.openexchange.hazelcast.network.join.static.nodes'' to allow joining, however, it's recommended to list all nodes in the cluster here&lt;br /&gt;
&lt;br /&gt;
== Disable Cluster Features ==&lt;br /&gt;
&lt;br /&gt;
The Hazelcast based clustering features can be disabled with the following property changes:&lt;br /&gt;
* Disable cluster discovery by setting ''com.openexchange.hazelcast.network.join'' to ''empty'' in ''hazelcast.properties''&lt;br /&gt;
* Disable Hazelcast by setting ''com.openexchange.hazelcast.enabled'' to false in ''hazelcast.properties''&lt;br /&gt;
* Disable message based cache event invalidation by setting ''com.openexchange.caching.jcs.eventInvalidation'' to ''false'' in ''cache.properties''&lt;br /&gt;
&lt;br /&gt;
== Update from 6.22.1 to version 6.22.2 and above ==&lt;br /&gt;
&lt;br /&gt;
As hazelcast will be used by default for the distribution of sessions starting 6.22.2 you have to adjust hazelcast according to our old cache configuration. First of all it's important that you install the open-xchange-sessionstorage-hazelcast package. This package will add the binding between hazelcast and the internal session management. Next you have to set a cluster name to the cluster.properties file (see [[#Cluster Discovery Errors]]). Furthermore you will have to add one of the two discovery modes mentioned in [[#Cluster Discovery]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Updating a Cluster =&lt;br /&gt;
&lt;br /&gt;
Running a cluster means built-in failover on the one hand, but might require some attention when it comes to the point of upgrading the services on all nodes in the cluster. This chapter gives an overview about general concepts and hints for silent updates of the cluster.&lt;br /&gt;
&lt;br /&gt;
== The Big Picture ==&lt;br /&gt;
&lt;br /&gt;
Updating an OX App Suite cluster is possible in several ways. The involved steps always include&lt;br /&gt;
&lt;br /&gt;
* Update the software by updating the packages through the distro's repository / software update tool&lt;br /&gt;
* Update the database schemas (so-called update tasks)&lt;br /&gt;
&lt;br /&gt;
There are some precautions required, though.&lt;br /&gt;
&lt;br /&gt;
=== Update Tasks Management ===&lt;br /&gt;
&lt;br /&gt;
It is a feature of the OX App Suite middleware to automatically start update tasks on a database schema when a user tries to login whose context lives on that schema. For installations beyond a certain size, if you just update the OX App Suite software without special handling of the update tasks, user logins will trigger an uncontrolled storm of update tasks on the databases, potentially leading to resource contention, unnecessary long update tasks runtimes, excessive load on the database server, maybe even service outages.&lt;br /&gt;
&lt;br /&gt;
So one key element of every update strategy is to avoid user logins on nodes which have already been updated to the new software version, while the database schemas are still on the old version. There are two fundamentally different approaches to this goal: use either a full downtime, or use a rolling update strategy.&lt;br /&gt;
&lt;br /&gt;
We describe the update strategy in more detail in the next section. Note that these are still high-level outlines of the actual procedure, which requires additional details with regards to Hazelcast, given further down below.&lt;br /&gt;
&lt;br /&gt;
==== Full downtime approach ====&lt;br /&gt;
&lt;br /&gt;
The full downtime approach is quite straightforward and involves&lt;br /&gt;
&lt;br /&gt;
* shutdown of all OX middleware nodes&lt;br /&gt;
* update the software on all OX App Suite (middleware and frontend) nodes&lt;br /&gt;
* execute the update tasks in a controlled way from one OX node&lt;br /&gt;
* restore the service&lt;br /&gt;
&lt;br /&gt;
This is the most general approach and always available, even if the rolling approach is not available due to Hazelcast constraints.&lt;br /&gt;
&lt;br /&gt;
==== Rolling strategy ====&lt;br /&gt;
&lt;br /&gt;
It is possible to execute the update tasks decoupled from the real update of the rest from the cluster, days or even weeks ahead of time, with the following approach:&lt;br /&gt;
&lt;br /&gt;
* If the load situation allows for it, take one node out of the loadbalancer (we call it the upgrade node). Otherwise, add a dedicated upgrade node to your cluster, identically configured to the other middleware nodes.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node&lt;br /&gt;
* update the software on the upgrade node&lt;br /&gt;
* execute all update tasks from the update node.&lt;br /&gt;
&lt;br /&gt;
In the last step, users from affected schemas will be logged out and denied service while the update tasks are running on their database schema. This is typically a short unavailability (some minutes) for a small part (1000...7000 depending on the installation) of the user base. This unavailability is of much lower impact than the unavailability of a full downtime, but you still might want to do this in the off-business hours.&lt;br /&gt;
&lt;br /&gt;
This way you end up with the production cluster running on the old version of OX App Suite, with the database already being upgraded to the next version. This is explicitly a valid and supported configuration. This approach offers the advantage that update tasks can be executed in advance, instead of doing them while the whole system is in a full maintenance downtime. Since update tasks can take some time, this is a considerable advantage.&lt;br /&gt;
&lt;br /&gt;
For the actual upgrade of the production cluster, the remaining steps are:&lt;br /&gt;
&lt;br /&gt;
* Upgrade and restart the OX App Suite software on one middleware node after another, one by one&lt;br /&gt;
* Upgrade the software on the OX App Suite frontend nodes (if these are separate nodes from the middleware nodes)&lt;br /&gt;
&lt;br /&gt;
Hazelcast will ensure that sessions from nodes which you restart are taken over by other nodes in the cluster, so ideally this step works without losing user sessions.&lt;br /&gt;
&lt;br /&gt;
For the rolling strategy to work as described, it is required that the old and new version of OX App Suite use compatible versions of the Hazelcast library. This is the case for most upgrades. However some upgrades must handle the situation that the new version of OX App Suite ships with a new version of Hazelcast incompatible to the version of Hazelcast shipped with the old version of OX App Suite. It will be stated in the release notes if this is the case for a given release. If so, then some additional steps are required during a rolling update to ensure session handling / invalidating during update tasks works properly. See below.&lt;br /&gt;
&lt;br /&gt;
== HOWTO / step-by-step instructions ==&lt;br /&gt;
&lt;br /&gt;
* Take backups of as much as possible (databases, OX config files, etc).&lt;br /&gt;
* Announce the maintenance to the users. The communication depends on which approach you chose: the full downtime approach will come with a full downtime for all users, while the rolling upgrade approach will result in some users will have a short loss of service while their schema upgrades.&lt;br /&gt;
&lt;br /&gt;
=== Full downtime approach ===&lt;br /&gt;
&lt;br /&gt;
* Initiate maintenance: Block HTTP sessions to the service. Put a reasonable maintenance page in place, probably some HTTP error 503 with a reasonable Retry-After header.&lt;br /&gt;
* Shutdown the service on all middleware nodes. Upgrade the software on all middleware and frontend nodes using the disto's package manager. See [[AppSuite:UpdatingOXPackages]] for details on how to do that. Don't forget the &amp;lt;code&amp;gt;touch-appsuite&amp;lt;/code&amp;gt; step if required (&amp;quot;If you update only UI plugins without simultaneously upgrading the core UI packages to a new version&amp;quot;).&lt;br /&gt;
* Start the &amp;lt;code&amp;gt;open-xchange&amp;lt;/code&amp;gt; service on one node&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that, in particular the [[UpdateTasks#How_to_see_all_schemas.3F|section]] about limited parallel execution.&lt;br /&gt;
* Start the &amp;lt;code&amp;gt;open-xchange&amp;lt;/code&amp;gt; services on the middleware nodes.&lt;br /&gt;
* Perform some crosschecks like&lt;br /&gt;
** all middleware nodes joined the Hazelcast cluster&lt;br /&gt;
** all OSGI bundles (which are expected to be running) are running&lt;br /&gt;
** WebUI login is possible&lt;br /&gt;
** Some central functionality tests like sending mails, accessing drive, etc&lt;br /&gt;
* Restore service: allow HTTP sessions, remove the maintenance page.&lt;br /&gt;
&lt;br /&gt;
=== Rolling Upgrade without breaking Hazelcast upgrade ===&lt;br /&gt;
&lt;br /&gt;
Remember: as stated above, this is viable only if the release notes for the new version do not state that there are breaking Hazelcast changes. For example, with v7.8.4 there were breaking Hazelcast changes and in the Release Notes it was stated as follows.&lt;br /&gt;
&lt;br /&gt;
https://software.open-xchange.com/products/appsuite/doc/Release_Notes_for_Release_7.8.4_2017-05-23.pdf&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Important - Please Note&lt;br /&gt;
&lt;br /&gt;
There is a major Hazelcast library update to OX App Suite v7.8.4. This means that when updating from an earlier backend version, due to the upgraded library, it is not possible to form a cluster of nodes that run previous version of Hazelcast (i.e. exiting volatile data in the cluster will be lost during the update). A consistent Hazelcast cluster is needed for cluster-wide cache invalidation. To circumvent problems with database update tasks that need to perform cache invalidation, please follow the steps described here: http://oxpedia.org/wiki/index.php?title=AppSuite:Running_a_cluster#Upgrades_of_the_Hazelcast_library. Please also note that session migration is not possible between versions. This usually affects all user sessions that are stored in a distributed map, and will require the users to re-login after the update. Running incompatible versions of Hazelcast within a cluster will result in logentries showing the conflicting node and version information.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you find you are upgrading to a version with breaking Hazelcast changes, please consult the next section [[#Rolling_Upgrade_with_breaking_Hazelcast_upgrade]].&lt;br /&gt;
&lt;br /&gt;
Pre-update:&lt;br /&gt;
&lt;br /&gt;
* Take one middleware node (the upgrade node) out of the HTTP traffic by adjusting the apache mod_proxy tables. We propose a combination of the balancer_manager to do this during runtime without restart, but also update the config files to prevent service restarts of apache to accidentally route sessions to the upgrade node.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node &lt;br /&gt;
* Update packages on the upgrade node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that. You might want to keep the load low on the DBs, to affect production operations as low as possible, and because with this decoupled update tasks approach there is no immediate time pressure. If you want to follow the [[UpdateTasks#How_to_see_all_schemas.3F|limited parallel]] approach, use a small, mild parallelity factor (e.g. 2 or maybe 4 if you know this by far does not saturate your DB platform).&lt;br /&gt;
&lt;br /&gt;
Real Update:&lt;br /&gt;
&lt;br /&gt;
* For one middleware cluster node after each nother:&lt;br /&gt;
** Update packages on that middleware node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
** Verify the node starts its bundles, joins the Hazelcast cluster, log files are clean, the node handles sessions&lt;br /&gt;
* For one frontend node after each other (if you've got separate frontend nodes):&lt;br /&gt;
** Update packages on that frontend node. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Finally, execute &amp;lt;code&amp;gt;touch-appsuite&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;--timestamp&amp;lt;/code&amp;gt; argument as described on the page [[AppSuite:UpdatingOXPackages]]&lt;br /&gt;
* Perform final crosschecks like&lt;br /&gt;
** all middleware nodes joined the Hazelcast cluster&lt;br /&gt;
** all OSGI bundles (which are expected to be running) are running&lt;br /&gt;
** WebUI login is possible&lt;br /&gt;
** Some central functionality tests like sending mails, accessing drive, etc&lt;br /&gt;
&lt;br /&gt;
=== Rolling Upgrade with breaking Hazelcast upgrade ===&lt;br /&gt;
&lt;br /&gt;
Cf [[#Upgrades_of_the_Hazelcast_library]] below.&lt;br /&gt;
&lt;br /&gt;
In principle the steps given in the previous section apply. However the upgrade needs to get the special Hazelcast Upgrade Package installed (e.g. one from &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-76x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-780-782&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-783&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-784&amp;lt;/code&amp;gt;, ...) during execution of the update tasks.&lt;br /&gt;
&lt;br /&gt;
So the pre-update steps look like:&lt;br /&gt;
&lt;br /&gt;
* Take one middleware node (the upgrade node) out of the HTTP traffic by adjusting the apache mod_proxy tables. We propose a combination of the balancer_manager to do this during runtime without restart, but also update the config files to prevent service restarts of apache to accidentally route sessions to the upgrade node.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node &lt;br /&gt;
* Update packages on the upgrade node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Install the special Hazelcast Upgrade Package on the upgrade node (e.g. one from &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-76x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-780-782&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-783&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-784&amp;lt;/code&amp;gt;, ...). Restart the service again.&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that. You might want to keep the load low on the DBs, to affect production operations as low as possible, and because with this decoupled update tasks approach there is no immediate time pressure. If you want to follow the [[UpdateTasks#How_to_see_all_schemas.3F|limited parallel]] approach, use a small, mild parallelity factor (e.g. 2 or maybe 4 if you know this by far does not saturate your DB platform).&lt;br /&gt;
&lt;br /&gt;
Note: don't worry if you don't see the upgrade node joining the legacy cluster: the upgrade node will not join the legacy cluster / not be visisble there since the upgrade node will be a so-called &amp;quot;native client&amp;quot; to the legacy cluster, and it will be created on the fly (and subsequently disposed again) for propagating an event. So also on &amp;lt;code&amp;gt;netstat&amp;lt;/code&amp;gt; level the upgrade node will not have visible connections to the legacy cluster (unless for the very short timeframe when an actual even is sent). You can verify the functionality of that package by log lines like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; Successfully initialzed Hazelcast client: &amp;lt;client-id&amp;gt;&lt;br /&gt;
 Successfully got reference to cache event topic: cacheEvents-3&lt;br /&gt;
 Publishing legacy cache event: &amp;lt;cache-event&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Successfully published legacy cache event, shutting down client after 546ms...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the overly prudent it might be an idea to prepare a special test context with a test user living in its dedicated (test) schema, so you can test the functionality of this mechanis during upgrade first.&lt;br /&gt;
&lt;br /&gt;
After the DB update tasks you can remove the special upgrade package again from the upgrade node.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Real Upgrade&amp;quot; procedure then looks like [[#Rolling_Upgrade_without_breaking_Hazelcast_upgrade|above]].&lt;br /&gt;
&lt;br /&gt;
== Reference Documentation ==&lt;br /&gt;
&lt;br /&gt;
=== Limitations ===&lt;br /&gt;
&lt;br /&gt;
While in most cases a seamless, rolling upgrade of all nodes in the cluster is possible, there may be situations where nodes running a newer version of the Open-Xchange Server are not able to communicate with older nodes in the cluster, i.e. can't access distributed data or consume incompatible event notifications - especially, when the underlying Hazelcast library is part of the update, which does not support this scenario at the moment. In such cases, the release notes will contain corresponding information, so please have a look there before applying an update.&lt;br /&gt;
&lt;br /&gt;
Additionally, there may always be some kind of race conditions during an update, i.e. client requests that can't be completed successfully or internal events not being deliverd to all nodes in the cluster. That's why the following information should only serve as a best-practices guide to minimize the impact of upgrades to the user experience.&lt;br /&gt;
&lt;br /&gt;
=== Upgrading a single Node ===&lt;br /&gt;
&lt;br /&gt;
Upgrading all nodes in the cluster should usually be done sequentially, i.o.w. one node after the other. This means that during the upgrade of one node, the node is temporarily disconnected from the other nodes in the cluster, and will join the cluster again after the update is completed. From the backend perspective, this is as easy as stopping the open-xchange service. other nodes in the cluster will recognize the disconnected node and start to repartition the shared cluster data automatically. But wait a minute - doing so would potentially lead to the webserver not registering the node being stopped immediately, resulting in temporary errors for currently logged in users until they are routed to another machine in the cluster. That's why it's good practice to tell the webserver's load balancer that the node should no longer fulfill incoming requests. The Apache Balancer Manager is an excellent tool for this ([http://httpd.apache.org/docs/2.2/mod/mod_status.html module ''mod_status'']). Look at the screen shot. Every node can be put into a disabled mode. Further requests will the redirected to other nodes in the cluster:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:balancer_manager.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Afterwards, the open-xchange service on the disabled node can be stopped by executing:&lt;br /&gt;
&lt;br /&gt;
 $ /etc/init.d/open-xchange stop&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 $ service open-xchange stop&lt;br /&gt;
&lt;br /&gt;
Now, the node is effectively in maintenance mode and any updates can take place. One could now verify the changed cluster infrastructure by accessing the Hazelcast MBeans either via JMX or the ''showruntimestats -c'' commandline tool (see above for details). There, the shut down node should no longer appear in the 'Member' section (com.hazelcast:type=Member).&lt;br /&gt;
&lt;br /&gt;
When all upgrades are processed, the node open-xchange service can be started again by executing:&lt;br /&gt;
&lt;br /&gt;
 $ /etc/init.d/open-xchange start&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 $ service open-xchange start&lt;br /&gt;
&lt;br /&gt;
As stated above, depending on the chosen cluster discovery mechanism, it might take some time until the node joins the cluster again. When using static cluster discovery, it will join the existing cluster usually directly during serivce startup, i.o.w. before other depending OSGi services are started. Otherwise, there might also be situations where the node cannot join the cluster directly, for example when there were no mDNS advertisments for other nodes in the cluster received yet. Then, it can take some additional time until the node finally joins the cluster. During startup of the node, you can observe the JMX console or the output of ''showruntimestats -c'' (com.hazelcast:type=Member) of another node in the cluster to verify when the node has joined. &lt;br /&gt;
&lt;br /&gt;
After the node has joined, distributed data is re-partioned automatically, and the node is ready to server incoming requests again - so now the node can finally be enabled again in the load balancer configuration of the webserver. Afterwards, the next node in the cluster can be upgraded using the same procedure, until all nodes were processed.&lt;br /&gt;
&lt;br /&gt;
=== Upgrades of the Hazelcast library ===&lt;br /&gt;
&lt;br /&gt;
In case an upgrade includes a major update of the Hazelcast library, a newly upgraded node will usually not be able to connect to the nodes running the previous version. In this case, volatile cluster data is lost after all nodes in the cluster have been updated, including sessions held in the distributed session storage. As outlined above, the release notes will contain a corresponding warning in such cases.&lt;br /&gt;
&lt;br /&gt;
Besides upgraded nodes not being able to access distributed data of the legacy cluster, this also affects new data not being available in the legacy cluster, which may cause troubles if the updated backend version needs to perform database update tasks. Database update tasks usually operate in a &amp;quot;blocking&amp;quot; way and all contexts associated with the schema being upgraded are disabled temporarily. Since context data itself is being held in caches on potentially each node in the cluster, the affected cache entries are invalidated during the database update. And, since cluster-wide cache invalidations again utilize Hazelcast functionality ([[#Remote Cache Invalidation]]), such invalidations normally won't be propagated to nodes running a previous version of the Hazelcast library.&lt;br /&gt;
&lt;br /&gt;
To work around this specific scenario where an incompatible upgrade of the Hazelcast library needs to be performed along with blocking database update tasks, starting with v7.8.0, a supplementary package is available that explicitly enables the context cache invalidation of nodes running the previous Hazelcast library. This package follows the naming scheme ''open-xchange-cluster-upgrade-from-XXX'' (where XXX representing the version of the legacy version of the Open-Xchange server), and is available in the repositories for the updated server packages. This package should only be installed on the first node of the cluster that is going to be upgraded to the new version, and can be deactivated once the database upgrade tasks were executed successfully. &lt;br /&gt;
&lt;br /&gt;
Once installed, a legacy cluster is discovered based on the available information in the ''hazelcast.properties'' configuration file in case cluster discovery is set to ''static''. If ''multicast'' is used, there's an alternative option to configure at least one of the addresses of the legacy cluster via ''com.openexchange.hazelcast.network.client.nodes''.&lt;br /&gt;
&lt;br /&gt;
As an example, along with the server v7.8.0, a new package named ''open-xchange-cluster-upgrade-from-76x'' can be installed that aids in invalidating cluster server nodes running v7.6.x (which includes the Hazelcast library in version 3.2.4). Using this package, the recommended steps to update an OX cluster from version 7.6.x to version 7.8.0 would be:&lt;br /&gt;
# Pick a node from your cluster that you want to use for executing the database update tasks shipped with the new release&lt;br /&gt;
# Disable this node for incoming HTTP requests in your webserver configuration as described at [[#Upgrading a single Node]]&lt;br /&gt;
# Update the OX packages on this node, additionally install the package ''open-xchange-cluster-upgrade-from-76x''&lt;br /&gt;
# Restart the open-xchange services on this node&lt;br /&gt;
# Trigger the update task executions using the ''runUpdate'' commandline utitlty as described at [[UpdateTasks]]&lt;br /&gt;
# Once they are finished, uninstall the package ''open-xchange-cluster-upgrade-from-76x'' again&lt;br /&gt;
# Restart the open-xchange services on this node&lt;br /&gt;
# Re-enable the node for incoming HTTP requests in your webserver configuration as described at [[#Upgrading a single Node]]&lt;br /&gt;
# Upgrade all other nodes in the cluster as described at [[#Upgrading a single Node]]&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.0 through v7.8.2 (incl.) to v7.8.3 using the package named ''open-xchange-cluster-upgrade-from-780-782'', since v7.8.0 through v7.8.2 (incl.) utilize Hazelcast v3.5.x, while v7.8.3 uses Hazelcast v3.6.4&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.3 to v7.8.4 using the package named ''open-xchange-cluster-upgrade-from-783'', since v7.8.3 utilizes Hazelcast v3.7.1&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.4 to v7.10.0 using the package named ''open-xchange-cluster-upgrade-from-784'', since v7.8.4 utilizes Hazelcast v3.8.1&lt;br /&gt;
&lt;br /&gt;
'''Operations Note:''' The upgraded node will be added as so-called [http://docs.hazelcast.org/docs/2.3/manual/html/ch15.html Native Client] to the legacy Hazelcast Cluster.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Native Client enables you to do all Hazelcast operations without being a member of the cluster.&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
However Native client is not member and relies on one of the cluster members.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means, the upgraded node will not be visible in the members list of the legacy Hazelcast cluster (&amp;lt;code&amp;gt;showruntimestats -c&amp;lt;/code&amp;gt;). Furthermore, the native client will created and destructed on single context events, with the effect that connections will only be visible in the very moment of such an event. This means effectively that verification of the invalidation mechanis is only possible by actually executing the &amp;lt;code&amp;gt;runupdate&amp;lt;/code&amp;gt; CLT. This should produce log lines like&lt;br /&gt;
&lt;br /&gt;
 Successfully initialzed Hazelcast client: &amp;lt;client-id&amp;gt;&lt;br /&gt;
 Successfully got reference to cache event topic: cacheEvents-3&lt;br /&gt;
 Publishing legacy cache event: &amp;lt;cache-event&amp;gt;&lt;br /&gt;
 Successfully published legacy cache event, shutting down client after 546ms...&lt;br /&gt;
&lt;br /&gt;
Most importantly, you should be able to observe correct functionality (users of affected contexts being logged out). It may be handy to prepare a dedicated schema with just test contexts inside. (How to create this is out of scope here, but hint: use &amp;lt;code&amp;gt;createschema&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;createcontext --schema-name&amp;lt;/code&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
=== Other Considerations ===&lt;br /&gt;
&lt;br /&gt;
* It's always recommended to only upgrade one node after the other, always ensuring that the cluster has formed correctly between each shutdown/startup of a node.&lt;br /&gt;
* Do not stop a node while running the runUpdate script or the associated update task.&lt;br /&gt;
* During the time of such a rolling upgrade of all nodes, we have effectively heterogeneous software versions in the cluster, which potentially might lead to temporary inconsistencies. Therefore, all nodes in the cluster should be updated in one cycle (but still one after the other).&lt;br /&gt;
* Following the above guideline, it's also possible to add or remove nodes dynamically to the cluster, not only when disconnecting a node temporary for updates.&lt;br /&gt;
* In case of trouble, i.e. a node refuses to join the cluster again after restart, consult the logfiles first for any hints about what is causing the problem - both on the disconnected node, and also on other nodes in the network&lt;br /&gt;
* If there are general incompatibilities between two revisions of the Open-Xchange Server that prevent an operation in a cluster (release notes), it's recommended to choose another name for the cluster in ''cluster.properties'' for the nodes with the new version. This will temporary lead to two separate clusters during the rolling upgrade, and finally the old cluster being shut down completely after the last node was updated to the new version. While distributed data can't be migrated from one server version to another in this scenario due to incompatibilities, the uptime of the system itself is not affected, since the nodes in the new cluster are able to serve new incoming requests directly.&lt;br /&gt;
* When updating only UI plugins without also updating to a new version of the core UI, you also need to perform the additional step from [[AppSuite:UpdatingOXPackages#Updating_UI_plugins|Updating UI plugins]].&lt;br /&gt;
&lt;br /&gt;
[[Category: AppSuite]] [[Category: Administration]] [[Category: Cluster]]&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Running_a_cluster&amp;diff=23787</id>
		<title>AppSuite:Running a cluster</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Running_a_cluster&amp;diff=23787"/>
		<updated>2017-12-13T08:08:46Z</updated>

		<summary type="html">&lt;p&gt;Dominik.epple: /* Rolling Upgrade without breaking Hazelcast upgrade */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Running a cluster&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Concepts =&lt;br /&gt;
&lt;br /&gt;
For inter-OX-communication over the network, multiple Open-Xchange servers can form a cluster. This brings different advantages regarding distribution and caching of volatile data, load balancing, scalability, fail-safety and robustness. Additionally, it provides the infrastructure for upcoming features of the Open-Xchange server. &lt;br /&gt;
The clustering capabilities of the Open-Xchange server are mainly built up on [http://hazelcast.com Hazelcast], an open source clustering and highly scalable data distribution platform for Java. The following article provides an overview about the current featureset and configuration options.&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
== Synchronized system clock times ==&lt;br /&gt;
It is crucial that all involved members in a cluster do have their system clock times in sync with each other; e.g. by using an NTP service.&lt;br /&gt;
&lt;br /&gt;
== HTTP routing ==&lt;br /&gt;
An OX cluster is always part of a larger picture. Usually there is front level loadbalancer as central HTTPS entry point to the platform. This loadbalancer optionally performs HTTPS termination and forwards HTTP(S) requests to webservers (the usual and only supported choice as of now is Apache). These webservers are performing HTTPS termination (if this is not happening on the loadbalancer) and serve static content, and (which is what is relevant for our discussion here) they forward dynamic requests to the OX backends.&lt;br /&gt;
&lt;br /&gt;
A central requirement for the interaction of these components (loadbalancer, webservers, OX nodes) is that we have session stability based on the JSESSIONID cookie / jsessionid path component suffix. This means that our application sets a cookie named JSESSIONID which has a value like &amp;lt;large decimal number&amp;gt;.&amp;lt;route identifier&amp;gt;, e.g. &amp;quot;5661584529655240315.OX1&amp;quot;. The route identifier here (&amp;quot;OX1&amp;quot; in this example) is taken by the OX node from a configuration setting from a config file and is specific to one OX node. HTTP routing must happen such that HTTP requests with a cookie with such a suffix always end up the corresponding OX node. There are furthermore specific cirumstances when passing this information via cookie is not possible. Then the JSESSIONID is transferred in a path component as &amp;quot;jsessionid=...&amp;quot; in the HTTP request. The routing mechanism needs to take that into account also.&lt;br /&gt;
&lt;br /&gt;
There are mainly two options to implement this. If the Apache processes are running co-located on the same machines running the OX groupware processes, it is often desired to have the front level loadbalancer perform HTTP routing to the correct machines. If dedicated Apache nodes are employed, is is usually sufficient to have the front-level loadbalancer do HTTP routing to the Apache nodes in a round-robin fashion and perform routing to the correct OX nodes in the Apache nodes.&lt;br /&gt;
&lt;br /&gt;
We provide sample configuration files to configure Apache (with mod_proxy_http) to perform HTTP routing correctly in our guides on OXpedia, e.g. [[AppSuite:Main_Page_AppSuite#quickinstall]]. Central elements are the directives &amp;quot;ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On&amp;quot; in conjunction with the &amp;quot;route=OX1&amp;quot; parameters to the BalancerMember lines in the Proxy definition. This is valid for Apache 2.2 as of Sep-2014.&lt;br /&gt;
&lt;br /&gt;
How to configure a front level loadbalancer to perform HTTP equivalent HTTP routing is dependent on the specific loadbalancer implementation. If Apache is used as front level loadbalancer, the same configuration as discussed in the previous section can be employed. As of time of writing this text (Sep 2014), the alternative choices are thin. F5 BigIP is reported to be able to implement &amp;quot;jsessionid based persistence using iRules&amp;quot;. nginx has the functionality in their commercial &amp;quot;nginx plus&amp;quot; product. (Both of these options have not been tested by OX.) Other loadbalancers with this functionality are not known to us.&lt;br /&gt;
&lt;br /&gt;
If the front level loadbalancer is not capable of performing correct HTTP routing, is is required to configure correct HTTP routing on Apache level, even if Apache runs co-located on the OX nodes and thus cross-routing happens.&lt;br /&gt;
&lt;br /&gt;
There are several reasons why we require session stability in exactly this way. We require session stabilty for horizontal scale-out; while we support transparent resuming / migration of user sessions in the OX cluster without need for users to re-authenticate, sessions wandering around randomly will consume a fixed amount resources corresponding to a running session on each OX node in the cluster, while a session sticky to one OX node will consume this fixed amount of resources only on one OX node. Furthermore there are mechanisms in OX like TokenLogin which work only of all requests beloning to one sequence get routed to the same OX node even if they stem from different machines with different IPs. Only the JSESSIONID (which in this case is transferred as jsessionid path component, as cookies do not work during a 302 redirect, which is part of this sequence) carries the required information where the request must be routed to.&lt;br /&gt;
&lt;br /&gt;
Usual &amp;quot;routing based on cookie hash&amp;quot; is not sufficient here since it disregards the information which machine originally issued the cookie. It only ensures that the session will be sticky to any target, which statistically will not be the same machine that issued the cookie. OX will then set a new JSESSIONID cookie, assuming the session had been migrated. The loadbalancer will then route the session to a different target, as the hash of the cookie will differ. This procedure then happens iteratively until by chance the routing based on cookie hash will route the session to the correct target. By then, a lot of resources will have been wasted, by creating full (short-term) sessions on all OX nodes. Furthermore, processes like TokenLogin will not work this way.&lt;br /&gt;
&lt;br /&gt;
= Configuration =&lt;br /&gt;
&lt;br /&gt;
All settings regarding cluster setup are located in the configuration file ''hazelcast.properties''. The former used additional files ''cluster.properties'', ''mdns.properties'' and ''static-cluster-discovery.properties'' are no longer needed. The following gives an overview about the most important settings - please refer to the inline documentation of the configuration file for more advanced options.&lt;br /&gt;
&lt;br /&gt;
Note: The configuration guide targets v7.4.0 of the OX server (and above). For older versions, please consult the history of this page. A full list of Hazelcast-related properties is available at https://documentation.open-xchange.com/components/middleware/config/7.8.4/#mode=features&amp;amp;feature=Hazelcast .&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
To restrict access to the cluster and to separate the cluster from others in the local network, a name and password needs to be defined. Only backend nodes having the same values for those properties are able to join and form a cluster. &lt;br /&gt;
&lt;br /&gt;
 # Configures the name of the cluster. Only nodes using the same group name &lt;br /&gt;
 # will join each other and form the cluster. Required if &lt;br /&gt;
 # &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is not &amp;quot;empty&amp;quot; (see below).&lt;br /&gt;
 com.openexchange.hazelcast.group.name=&lt;br /&gt;
 &lt;br /&gt;
 # The password used when joining the cluster. Defaults to &amp;quot;wtV6$VQk8#+3ds!a&amp;quot;. &lt;br /&gt;
 # Please change this value, and ensure it's equal on all nodes in the cluster.&lt;br /&gt;
 com.openexchange.hazelcast.group.password=wtV6$VQk8#+3ds!a&lt;br /&gt;
&lt;br /&gt;
== Network ==&lt;br /&gt;
&lt;br /&gt;
It's required to define the network interface that is used for cluster communication via ''com.openexchange.hazelcast.network.interfaces''. By default, the interface is restricted to the local loopback address only. To allow the same configuration amongst all nodes in the cluster, it's recommended to define the value using a wildcard matching the IP addresses of all nodes participating in the cluster, e.g. ''192.168.0.*''&lt;br /&gt;
&lt;br /&gt;
 # Comma-separated list of interface addresses hazelcast should use. Wildcards &lt;br /&gt;
 # (*) and ranges (-) can be used. Leave blank to listen on all interfaces&lt;br /&gt;
 # Especially in server environments with multiple network interfaces, it's &lt;br /&gt;
 # recommended to specify the IP-address of the network interface to bind to &lt;br /&gt;
 # explicitly. Defaults to &amp;quot;127.0.0.1&amp;quot; (local loopback only), needs to be &lt;br /&gt;
 # adjusted when building a cluster of multiple backend nodes.&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=127.0.0.1&lt;br /&gt;
&lt;br /&gt;
To form a cluster of multiple OX server nodes, different discovery mechanisms can be used. The discovery mechanism is specified via the property ''com.openexchange.hazelcast.network.join'':&lt;br /&gt;
&lt;br /&gt;
 # Specifies which mechanism is used to discover other backend nodes in the &lt;br /&gt;
 # cluster. Possible values are &amp;quot;empty&amp;quot; (no discovery for single-node setups),&lt;br /&gt;
 # &amp;quot;static&amp;quot; (fixed set of cluster member nodes) or &amp;quot;multicast&amp;quot; (automatic &lt;br /&gt;
 # discovery of other nodes via multicast). Defaults to &amp;quot;empty&amp;quot;. Depending on &lt;br /&gt;
 # the specified value, further configuration might be needed, see &amp;quot;Networking&amp;quot;&lt;br /&gt;
 # section below. &lt;br /&gt;
 com.openexchange.hazelcast.network.join=empty&lt;br /&gt;
&lt;br /&gt;
Generally, it's advised to use the same network join mechanism for all nodes in the cluster, and, in most cases, it's strongly recommended to use a ''static'' network join configuration. This will allow the nodes to join the cluster directly upon startup. With a ''multicast'' based setup, nodes will merge to an existing cluster possibly at some later time, thus not being able to access the distributed data until they've joined.&lt;br /&gt;
&lt;br /&gt;
Depending on the network join setting, further configuration may be necessary, as decribed in the following paragraphs.&lt;br /&gt;
&lt;br /&gt;
=== empty ===&lt;br /&gt;
&lt;br /&gt;
When using the default value ''empty'', no other nodes are discovered in the cluster. This value is suitable for single-node installations. Note that other nodes that are configured to use other network join mechanisms may be still able to still to connect to this node, e.g. using a ''static'' network join, having the IP address of this host in the list of potential cluster members (see below).&lt;br /&gt;
&lt;br /&gt;
=== static ===&lt;br /&gt;
&lt;br /&gt;
The most common setting for ''com.openexchange.hazelcast.network.join'' is ''static''. A static cluster discovery uses a fixed list of IP addresses of the nodes in the cluster. During startup and after a specific interval, the underlying Hazelcast library probes for not yet joined nodes from this list and adds them to the cluster automatically. The address list is configured via ''com.openexchange.hazelcast.network.join.static.nodes'':&lt;br /&gt;
&lt;br /&gt;
 # Configures a comma-separated list of IP addresses / hostnames of possible &lt;br /&gt;
 # nodes in the cluster, e.g. &amp;quot;10.20.30.12, 10.20.30.13:5701, 192.178.168.110&amp;quot;.&lt;br /&gt;
 # Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set to &amp;quot;static&amp;quot;. &lt;br /&gt;
 # It doesn't hurt if the address of the local host appears in the list, so &lt;br /&gt;
 # that it's still possible to use the same list throughout all nodes in the &lt;br /&gt;
 # cluster.&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=&lt;br /&gt;
&lt;br /&gt;
For a fixed set of backend nodes, it's recommended to simply include the IP addresses of all nodes in the list, and use the same configuration for each node. However, it's only required to add the address of at least one other node in the cluster to allow the node to join the cluster. Also, when adding a new node to the cluster and this list is extended accordingly, existing nodes don't need to be shut down to recognize the new node, as long as the new node's address list contains at least one of the already running nodes. &lt;br /&gt;
&lt;br /&gt;
=== multicast ===&lt;br /&gt;
&lt;br /&gt;
For highly dynamic setups where nodes are added and removed from the cluster quite often and/or the host's IP addresses are not fixed, it's also possible to configure the network join via multicast. During startup and after a specific interval, the backend nodes initiate the multicast join process automatically, and discovered nodes form or join the cluster afterwards. The multicast group and port can be configured as follows:&lt;br /&gt;
&lt;br /&gt;
 # Configures the multicast address used to discover other nodes in the cluster&lt;br /&gt;
 # dynamically. Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set &lt;br /&gt;
 # to &amp;quot;multicast&amp;quot;. If the nodes reside in different subnets, please ensure that &lt;br /&gt;
 # multicast is enabled between the subnets. Defaults to &amp;quot;224.2.2.3&amp;quot;. &lt;br /&gt;
 com.openexchange.hazelcast.network.join.multicast.group=224.2.2.3&lt;br /&gt;
 &lt;br /&gt;
 # Configures the multicast port used to discover other nodes in the cluster&lt;br /&gt;
 # dynamically. Only used if &amp;quot;com.openexchange.hazelcast.network.join&amp;quot; is set &lt;br /&gt;
 # to &amp;quot;multicast&amp;quot;. Defaults to &amp;quot;54327&amp;quot;. &lt;br /&gt;
 com.openexchange.hazelcast.network.join.multicast.port=54327&lt;br /&gt;
&lt;br /&gt;
== Example ==&lt;br /&gt;
&lt;br /&gt;
The following example shows how a simple cluster named ''MyCluster'' consisting of 4 backend nodes can be configured using ''static'' cluster discovery. The node's IP addresses are 10.0.0.15, 10.0.0.16, 10.0.0.17 and 10.0.0.18. Note that the same ''hazelcast.properties'' is used by all nodes.&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.group.name=MyCluster&lt;br /&gt;
 com.openexchange.hazelcast.group.password=secret&lt;br /&gt;
 com.openexchange.hazelcast.network.join=static&lt;br /&gt;
 com.openexchange.hazelcast.network.join.static.nodes=10.0.0.15,10.0.0.16,10.0.0.17,10.0.0.18&lt;br /&gt;
 com.openexchange.hazelcast.network.interfaces=10.0.0.*&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Advanced Configuration ==&lt;br /&gt;
&lt;br /&gt;
=== Lite Members (available since v7.8.4) ===&lt;br /&gt;
&lt;br /&gt;
Lite members in a Hazelcast cluster are members that do not hold any data partitions, i.e. all read- and write operations to distributed maps are delegated to non-lite (&amp;quot;full&amp;quot;) members. Apart from not having data partitions, lite members participate in the same way as other members: they can register listeners for distributed topics (e.g. cache invalidation events) or can be addressed for task execution (e.g. during realtime communication). &lt;br /&gt;
&lt;br /&gt;
Similar to using a custom partitioning scheme, separating the nodes of a large cluster into few &amp;quot;full&amp;quot; members and many &amp;quot;lite&amp;quot; members helps to minimize the impact of JVM activities from a single node (mainly the garbage collector) on the whole cluster communication. Additionally, when starting or stopping lite members, no repartitioning of the distributed cluster data needs to be performed, which significantly decreases the node's startup- and shutdown time and reduces the necessary network communication to a minimum. &lt;br /&gt;
&lt;br /&gt;
In medium or larger sized clusters, it is sufficient to have roughly 10 to 20 percent of the nodes configured as &amp;quot;full&amp;quot; members, while all other ones can be started as &amp;quot;lite&amp;quot; member nodes. Additionally, please note that the configured backup count in the map configurations should always be smaller than the total number of &amp;quot;full&amp;quot; members, otherwise, there may be problems if one of those data nodes is shut down temporarily for maintenance. So, the minimum number of &amp;quot;full&amp;quot; members is implicitly bound to the sum of a map's ''backupCount'' and ''asyncBackupCount'' properties, plus ''1'' for the original data partition. &lt;br /&gt;
&lt;br /&gt;
The configured &amp;quot;full&amp;quot; members should preferrably not be used to serve client requests (by not adding them as endpoint in the loadbalancer), to ensure they are always responsive. Also, shutdown and startups of those &amp;quot;full&amp;quot; members should be reduced to a minimum to avoid repartitioning operations. &lt;br /&gt;
&lt;br /&gt;
More general information regarding lite members is available at http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#enabling-lite-members .&lt;br /&gt;
&lt;br /&gt;
To configure a node as &amp;quot;lite&amp;quot; member, the following configuration should be applied in the node's ''hazelcast.properties'' file:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.liteMember=true&lt;br /&gt;
&lt;br /&gt;
It's also recommended to use a &amp;quot;static&amp;quot; cluster discovery for the network join, and list all &amp;quot;full&amp;quot; member nodes here, so that join requests are handled by those nodes, too (and not the other nodes that are potentially prone to garbage collection delays. &lt;br /&gt;
&lt;br /&gt;
=== Custom Partitioning ===&lt;br /&gt;
&lt;br /&gt;
Note: Starting with v7.8.4, &amp;quot;Lite Members&amp;quot; should be used in favor of applying a custom partitioning scheme.&lt;br /&gt;
&lt;br /&gt;
While originally being designed to separate the nodes holding distributed data into different risk groups for increased fail safety, a custom partitioning strategy may also be used to distinguish between nodes holding distributed data from those who should not. &lt;br /&gt;
&lt;br /&gt;
This approach of custom partitioning may be used in a OX cluster, where usually different backend nodes serve different purposes. A common scenario is that there are nodes handling requests from the web interfaces, and others being responsible for USM/EAS traffic. Due to their nature of processing large chunks of synchronization data in memory, the USM/EAS nodes may encounter small delays when the Java garbage collector kicks in and suspends the Java Virtual Machine. Since those delays may also have an influence on hazelcast-based communication in the cluster, the idea is to instruct hazelcast to not store distributed data on that nodes. This is where a custom partitioning scheme comes into play.&lt;br /&gt;
&lt;br /&gt;
To setup a custom partitioning scheme in the cluster, an additional ''hazelcast.xml'' configuration file is used, which should be placed into the ''hazelcast'' subdirectory of the OX configuration folder, usually at ''/opt/openexchange/etc/hazelcast''. Please note that it's vital that each node in the cluster is configured equally here, so the same ''hazelcast.xml'' file should be copied to each server. The configuration read from there is used as basis for all further settings that are taken from the ordinary ''hazelcast.properties'' config file. &lt;br /&gt;
&lt;br /&gt;
To setup a custom partitioning scheme, the partition groups must be defined in the ''hazelcast.xml'' file. See the following file for an example configuration, where the three nodes ''10.10.10.60'', ''10.10.10.61'' and ''10.10.10.62'' are defined to form an own partitioning group each. Doing so, all distributed data will be stored at one of those nodes physically, while the corresponding backup data (if configured) at one of the other two nodes. All other nodes in the cluster will not be used to store distributed data, but will still be &amp;quot;full&amp;quot; hazelcast members, which is necessary for other cluster-wide operations the OX backends use. &lt;br /&gt;
&lt;br /&gt;
Please note that the configured backup count in the map configurations should be smaller than the number of nodes here, otherwise, there may be problems if one of those data nodes is shut down temporarily for maintenance. So, the minimum number of nodes to define in the partition group sections is implicitly bound to the sum of a map's ''backupCount'' and ''asyncBackupCount'' properties, plus ''1'' for the original data partition. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
 &amp;lt;!--&lt;br /&gt;
   ~ Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.&lt;br /&gt;
   ~&lt;br /&gt;
   ~ Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
   ~ you may not use this file except in compliance with the License.&lt;br /&gt;
   ~ You may obtain a copy of the License at&lt;br /&gt;
   ~&lt;br /&gt;
   ~ http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
   ~&lt;br /&gt;
   ~ Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
   ~ distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
   ~ See the License for the specific language governing permissions and&lt;br /&gt;
   ~ limitations under the License.&lt;br /&gt;
   --&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;hazelcast xsi:schemaLocation=&amp;quot;http://www.hazelcast.com/schema/config hazelcast-config-3.1.xsd&amp;quot;&lt;br /&gt;
            xmlns=&amp;quot;http://www.hazelcast.com/schema/config&amp;quot;&lt;br /&gt;
            xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;partition-group enabled=&amp;quot;true&amp;quot; group-type=&amp;quot;CUSTOM&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.60&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.61&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
         &amp;lt;member-group&amp;gt;&lt;br /&gt;
             &amp;lt;interface&amp;gt;10.10.10.62&amp;lt;/interface&amp;gt;&lt;br /&gt;
         &amp;lt;/member-group&amp;gt;&lt;br /&gt;
     &amp;lt;/partition-group&amp;gt;&lt;br /&gt;
 &amp;lt;/hazelcast&amp;gt;&lt;br /&gt;
&lt;br /&gt;
More general information regarding custom partioning is available at http://hazelcast.org/docs/latest/manual/html/partitiongroupconfig.html . &lt;br /&gt;
&lt;br /&gt;
It's also recommended to use a &amp;quot;static&amp;quot; cluster discovery for the network join, and list same the nodes that are also configured in the parition groups here, so that join requests are handled by those nodes, too (and not the other nodes that are potentially prone to garbage collection delays. &lt;br /&gt;
&lt;br /&gt;
After configuring a custom partitioning scheme, the data distribution may be verified, e.g. by inspecting the MBeans of the distributed maps via JMX.&lt;br /&gt;
&lt;br /&gt;
= Features =&lt;br /&gt;
&lt;br /&gt;
The following list gives an overview about different features that were implemented using the new cluster capabilities.&lt;br /&gt;
&lt;br /&gt;
== Distributed Session Storage ==&lt;br /&gt;
&lt;br /&gt;
Previously, when an Open-Xchange server was shutdown for maintenance, all user sessions that were bound to that machine were lost, i.e. the users needed to login again. With the distributed session storage, all sessions are backed by a distributed map in the cluster, so that they are no longer bound to a specific node in the cluster. When a node is shut down, the session data is still available in the cluster and can be accessed from the remaining nodes. The load-balancing techniques of the webserver then seamlessly routes the user session to another node, with no ''session expired'' errors. The distributed session storage comes with the package ''open-xchange-sessionstorage-hazelcast''. It's recommended to install this optional package in all clustered environments with multiple groupware server nodes.&lt;br /&gt;
&lt;br /&gt;
'''Notes:''' &lt;br /&gt;
* While there's some kind of built-in session distribution among the nodes in the cluster, this should not be seen as a replacement for session-stickiness between the loadbalancer and groupware nodes, i.e. one should still configure the webserver to use sticky sessions for performance reasons.&lt;br /&gt;
* The distributed session storage is still an in-memory storage. While the session data is distributed and backed up on multiple nodes in the cluster, shutting down multiple or all nodes at the same time will lead to loss of the the distributed data. To avoid such data loss when shutting down a node, please follow the guidelines at [[ Updating_a_Cluster ]].&lt;br /&gt;
&lt;br /&gt;
Depending on the cluster infrastructure, different backup-count configuration options might be set for the distributed session storage in the map configuration file ''sessions.properties'' in the ''hazelcast'' subdirectory:&lt;br /&gt;
&lt;br /&gt;
   com.openexchange.hazelcast.configuration.map.backupCount=1&lt;br /&gt;
&lt;br /&gt;
The ''backupcount'' property configures the number of nodes with synchronized backups. Synchronized backups block operations until backups are successfully copied and acknowledgements are received. If 1 is set as the backup-count for example, then all entries of the map will be copied to another JVM for fail-safety. 0 means no backup. Any integer between 0 and 6. Default is 1, setting bigger than 6 has no effect.&lt;br /&gt;
&lt;br /&gt;
   com.openexchange.hazelcast.configuration.map.asyncBackupCount=0&lt;br /&gt;
&lt;br /&gt;
The ''asyncbackup'' property configures the number of nodes with async backups. Async backups do not block operations and do not require acknowledgements. 0 means no backup. Any integer between 0 and 6. Default is 0, setting bigger than 6 has no effect.&lt;br /&gt;
&lt;br /&gt;
Since session data is backed up by default continuously by multiple nodes in the cluster, the steps described in [[ Session_Migration ]] to trigger session migration to other nodes explicitly is obsolete and no longer needed with the distributed session storage.&lt;br /&gt;
&lt;br /&gt;
Normally, sessions in the distributed storages are not evicted automatically, but are only removed when they're also removed from the session handler, either due to a logout operation or when exceeding the long-term session lifetime as configured by ''com.openexchange.sessiond.sessionLongLifeTime'' in ''sessiond.properties''. Under certain circumstances, i.e. the session is no longer accessed by the client and the OX node hosting the session in it's long-life container being shutdown, the remove operation from the distributed storage might not be triggered. Therefore, additionaly a maximum idle time of map-entries can be configured for the distributed sessions map via &lt;br /&gt;
&lt;br /&gt;
 com.openexchange.hazelcast.configuration.map.maxIdleSeconds=640000&lt;br /&gt;
&lt;br /&gt;
To avoid unnecessary eviction, the value should be higher than the configured ''com.openexchange.sessiond.sessionLongLifeTime'' in ''sessiond.properties''.&lt;br /&gt;
&lt;br /&gt;
== Remote Cache Invalidation ==&lt;br /&gt;
&lt;br /&gt;
For faster access, groupware data is held in different caches by the server. Formerly, the caches utilized the TCP Lateral Auxiliary Cache plug in (LTCP) for the underlying JCS caches to broadcast updates and removals to caches on other OX nodes in the cluster. This could potentially lead to problems when remote invalidation was not working reliably due to network discovery problems. As an alternative, remote cache invalidation can also be performed using reliable publish/subscribe events built up on Hazelcast topics. This can be configured in the ''cache.properties'' configuration file, where the 'eventInvalidation' property can either be set to 'false' for the legacy behavior or 'true' for the new mechanism:&lt;br /&gt;
&lt;br /&gt;
 com.openexchange.caching.jcs.eventInvalidation=true&lt;br /&gt;
&lt;br /&gt;
All nodes participating in the cluster should be configured equally.&lt;br /&gt;
&lt;br /&gt;
Internally, if ''com.openexchange.caching.jcs.eventInvalidation'' is set to ''true'', LTCP is disabled in JCS caches. Instead, an internal mechanism based on distributed Hazelcast event topics is used to invalidate data throughout all nodes in the cluster after local update- and remove-operations. Put-operations aren't propagated (and haven't been with LTCP either), since all data put into caches can be locally loaded/evaluated at each node from the persistent storage layer.&lt;br /&gt;
&lt;br /&gt;
Using Hazelcast-based cache invalidation also makes further configuration of the JCS auxiliaries obsolete in the ''cache.ccf'' configuration file. In that case, all ''jcs.auxiliary.LTCP.*'' configuration settings are virtually ignored. However, it's still required to mark caches that require cluster-wide invalidation via ''jcs.region.&amp;lt;cache_name&amp;gt;=LTCP'', just as before. So basically, when using the new default setting ''com.openexchange.caching.jcs.eventInvalidation=true'', it's recommended to just use the stock ''cache.ccf'' file, since no further LTCP configuration is required.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
= Adminstration / Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
== Hazelcast Configuration ==&lt;br /&gt;
&lt;br /&gt;
The underlying Hazelcast library can be configured using the file ''hazelcast.properties''.&lt;br /&gt;
&lt;br /&gt;
'''Important''':&amp;lt;br&amp;gt;&lt;br /&gt;
By default property ''com.openexchange.hazelcast.network.interfaces'' is set to ''127.0.0.1''; meaning Hazelcast listens only to loop-back device. To build a cluster among remote nodes the appropriate network interface needs to be configured there. Leaving that property empty lets Hazelcast listen to all available network interfaces.&lt;br /&gt;
&lt;br /&gt;
The Hazelcast JMX MBean can be enabled or disabled with the property ''com.openexchange.hazelcast.jmx''. The properties ''com.openexchange.hazelcast.mergeFirstRunDelay'' and ''com.openexchange.hazelcast.mergeRunDelay'' control the run intervals of the so-called ''Split Brain Handler'' of Hazelcast that initiates the cluster join process when a new node is started. More details can be found at http://www.hazelcast.com/docs/2.5/manual/single_html/#NetworkPartitioning. &lt;br /&gt;
&lt;br /&gt;
The port ranges used by Hazelcast for incoming and outgoing connections can be controlled via the configuration parameters ''com.openexchange.hazelcast.networkConfig.port'', ''com.openexchange.hazelcast.networkConfig.portAutoIncrement'' and ''com.openexchange.hazelcast.networkConfig.outboundPortDefinitions''.&lt;br /&gt;
&lt;br /&gt;
== Commandline Tool ==&lt;br /&gt;
&lt;br /&gt;
To print out statistics about the cluster and the distributed data, the ''showruntimestats'' commandline tool can be executed witht the ''clusterstats'' ('c') argument. This provides an overview about the runtime cluster configuration of the node, other members in the cluster and distributed data structures.&lt;br /&gt;
&lt;br /&gt;
== JMX ==&lt;br /&gt;
&lt;br /&gt;
In the Open-Xchange server Java process, the MBean ''com.hazelcast'' can be used to monitor and manage different aspects of the underlying Hazelcast cluster. The ''com.hazelcast'' MBean provides detailed information about the cluster configuration and distributed data structures.&lt;br /&gt;
&lt;br /&gt;
== Hazelcast Errors ==&lt;br /&gt;
&lt;br /&gt;
When experiencing hazelcast related errors in the logfiles, most likely different versions of the packages are installed, leading to different message formats that can't be understood by nodes using another version. Examples for such errors are exceptions in hazelcast components regarding (de)serialization or other message processing.&lt;br /&gt;
This may happen when performing a consecutive update of all nodes in the cluster, where temporarily nodes with a heterogeneous setup try to communicate with each other. If the errors don't disappear after all nodes in the cluster have been update to the same package versions, it might be necessary to shutdown the cluster completely, so that all distributed data is cleared.&lt;br /&gt;
&lt;br /&gt;
== Cluster Discovery Errors ==&lt;br /&gt;
&lt;br /&gt;
* If the started OX nodes don't form a cluster, please double-check your configuration in ''hazelcast.properties''&lt;br /&gt;
* It's important to have the same cluster name defined in ''hazelcast.properties'' throughout all nodes in the cluster&lt;br /&gt;
* Especially when using multicast cluster discovery, it might take some time until the cluster is formed&lt;br /&gt;
* When using ''static'' cluster discovery, at least one other node in the cluster has to be configured in ''com.openexchange.hazelcast.network.join.static.nodes'' to allow joining, however, it's recommended to list all nodes in the cluster here&lt;br /&gt;
&lt;br /&gt;
== Disable Cluster Features ==&lt;br /&gt;
&lt;br /&gt;
The Hazelcast based clustering features can be disabled with the following property changes:&lt;br /&gt;
* Disable cluster discovery by setting ''com.openexchange.hazelcast.network.join'' to ''empty'' in ''hazelcast.properties''&lt;br /&gt;
* Disable Hazelcast by setting ''com.openexchange.hazelcast.enabled'' to false in ''hazelcast.properties''&lt;br /&gt;
* Disable message based cache event invalidation by setting ''com.openexchange.caching.jcs.eventInvalidation'' to ''false'' in ''cache.properties''&lt;br /&gt;
&lt;br /&gt;
== Update from 6.22.1 to version 6.22.2 and above ==&lt;br /&gt;
&lt;br /&gt;
As hazelcast will be used by default for the distribution of sessions starting 6.22.2 you have to adjust hazelcast according to our old cache configuration. First of all it's important that you install the open-xchange-sessionstorage-hazelcast package. This package will add the binding between hazelcast and the internal session management. Next you have to set a cluster name to the cluster.properties file (see [[#Cluster Discovery Errors]]). Furthermore you will have to add one of the two discovery modes mentioned in [[#Cluster Discovery]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Updating a Cluster =&lt;br /&gt;
&lt;br /&gt;
Running a cluster means built-in failover on the one hand, but might require some attention when it comes to the point of upgrading the services on all nodes in the cluster. This chapter gives an overview about general concepts and hints for silent updates of the cluster.&lt;br /&gt;
&lt;br /&gt;
== The Big Picture ==&lt;br /&gt;
&lt;br /&gt;
Updating an OX App Suite cluster is possible in several ways. The involved steps always include&lt;br /&gt;
&lt;br /&gt;
* Update the software by updating the packages through the distro's repository / software update tool&lt;br /&gt;
* Update the database schemas (so-called update tasks)&lt;br /&gt;
&lt;br /&gt;
There are some precautions required, though.&lt;br /&gt;
&lt;br /&gt;
=== Update Tasks Management ===&lt;br /&gt;
&lt;br /&gt;
It is a feature of the OX App Suite middleware to automatically start update tasks on a database schema when a user tries to login whose context lives on that schema. For installations beyond a certain size, if you just update the OX App Suite software without special handling of the update tasks, user logins will trigger an uncontrolled storm of update tasks on the databases, potentially leading to resource contention, unnecessary long update tasks runtimes, excessive load on the database server, maybe even service outages.&lt;br /&gt;
&lt;br /&gt;
So one key element of every update strategy is to avoid user logins on nodes which have already been updated to the new software version, while the database schemas are still on the old version. There are two fundamentally different approaches to this goal: use either a full downtime, or use a rolling update strategy.&lt;br /&gt;
&lt;br /&gt;
We describe the update strategy in more detail in the next section. Note that these are still high-level outlines of the actual procedure, which requires additional details with regards to Hazelcast, given further down below.&lt;br /&gt;
&lt;br /&gt;
==== Full downtime approach ====&lt;br /&gt;
&lt;br /&gt;
The full downtime approach is quite straightforward and involves&lt;br /&gt;
&lt;br /&gt;
* shutdown of all OX middleware nodes&lt;br /&gt;
* update the software on all OX App Suite (middleware and frontend) nodes&lt;br /&gt;
* execute the update tasks in a controlled way from one OX node&lt;br /&gt;
* restore the service&lt;br /&gt;
&lt;br /&gt;
This is the most general approach and always available, even if the rolling approach is not available due to Hazelcast constraints.&lt;br /&gt;
&lt;br /&gt;
==== Rolling strategy ====&lt;br /&gt;
&lt;br /&gt;
It is possible to execute the update tasks decoupled from the real update of the rest from the cluster, days or even weeks ahead of time, with the following approach:&lt;br /&gt;
&lt;br /&gt;
* If the load situation allows for it, take one node out of the loadbalancer (we call it the upgrade node). Otherwise, add a dedicated upgrade node to your cluster, identically configured to the other middleware nodes.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node&lt;br /&gt;
* update the software on the upgrade node&lt;br /&gt;
* execute all update tasks from the update node.&lt;br /&gt;
&lt;br /&gt;
In the last step, users from affected schemas will be logged out and denied service while the update tasks are running on their database schema. This is typically a short unavailability (some minutes) for a small part (1000...7000 depending on the installation) of the user base. This unavailability is of much lower impact than the unavailability of a full downtime, but you still might want to do this in the off-business hours.&lt;br /&gt;
&lt;br /&gt;
This way you end up with the production cluster running on the old version of OX App Suite, with the database already being upgraded to the next version. This is explicitly a valid and supported configuration. This approach offers the advantage that update tasks can be executed in advance, instead of doing them while the whole system is in a full maintenance downtime. Since update tasks can take some time, this is a considerable advantage.&lt;br /&gt;
&lt;br /&gt;
For the actual upgrade of the production cluster, the remaining steps are:&lt;br /&gt;
&lt;br /&gt;
* Upgrade and restart the OX App Suite software on one middleware node after another, one by one&lt;br /&gt;
* Upgrade the software on the OX App Suite frontend nodes (if these are separate nodes from the middleware nodes)&lt;br /&gt;
&lt;br /&gt;
Hazelcast will ensure that sessions from nodes which you restart are taken over by other nodes in the cluster, so ideally this step works without losing user sessions.&lt;br /&gt;
&lt;br /&gt;
For the rolling strategy to work as described, it is required that the old and new version of OX App Suite use compatible versions of the Hazelcast library. This is the case for most upgrades. However some upgrades must handle the situation that the new version of OX App Suite ships with a new version of Hazelcast incompatible to the version of Hazelcast shipped with the old version of OX App Suite. It will be stated in the release notes if this is the case for a given release. If so, then some additional steps are required during a rolling update to ensure session handling / invalidating during update tasks works properly. See below.&lt;br /&gt;
&lt;br /&gt;
== HOWTO / step-by-step instructions ==&lt;br /&gt;
&lt;br /&gt;
* Take backups of as much as possible (databases, OX config files, etc).&lt;br /&gt;
* Announce the maintenance to the users. The communication depends on which approach you chose: the full downtime approach will come with a full downtime for all users, while the rolling upgrade approach will result in some users will have a short loss of service while their schema upgrades.&lt;br /&gt;
&lt;br /&gt;
=== Full downtime approach ===&lt;br /&gt;
&lt;br /&gt;
* Initiate maintenance: Block HTTP sessions to the service. Put a reasonable maintenance page in place, probably some HTTP error 503 with a reasonable Retry-After header.&lt;br /&gt;
* Shutdown the service on all middleware nodes. Upgrade the software on all middleware and frontend nodes using the disto's package manager. See [[AppSuite:UpdatingOXPackages]] for details on how to do that. Don't forget the &amp;lt;code&amp;gt;touch-appsuite&amp;lt;/code&amp;gt; step.&lt;br /&gt;
* Start the &amp;lt;code&amp;gt;open-xchange&amp;lt;/code&amp;gt; service on one node&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that, in particular the [[UpdateTasks#How_to_see_all_schemas.3F|section]] about limited parallel execution.&lt;br /&gt;
* Start the &amp;lt;code&amp;gt;open-xchange&amp;lt;/code&amp;gt; services on the middleware nodes.&lt;br /&gt;
* Perform some crosschecks like&lt;br /&gt;
** all middleware nodes joined the Hazelcast cluster&lt;br /&gt;
** all OSGI bundles (which are expected to be running) are running&lt;br /&gt;
** WebUI login is possible&lt;br /&gt;
** Some central functionality tests like sending mails, accessing drive, etc&lt;br /&gt;
* Restore service: allow HTTP sessions, remove the maintenance page.&lt;br /&gt;
&lt;br /&gt;
=== Rolling Upgrade without breaking Hazelcast upgrade ===&lt;br /&gt;
&lt;br /&gt;
Remember: as stated above, this is viable only if the release notes for the new version do not state that there are breaking Hazelcast changes. For example, with v7.8.4 there were breaking Hazelcast changes and in the Release Notes it was stated as follows.&lt;br /&gt;
&lt;br /&gt;
https://software.open-xchange.com/products/appsuite/doc/Release_Notes_for_Release_7.8.4_2017-05-23.pdf&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Important - Please Note&lt;br /&gt;
&lt;br /&gt;
There is a major Hazelcast library update to OX App Suite v7.8.4. This means that when updating from an earlier backend version, due to the upgraded library, it is not possible to form a cluster of nodes that run previous version of Hazelcast (i.e. exiting volatile data in the cluster will be lost during the update). A consistent Hazelcast cluster is needed for cluster-wide cache invalidation. To circumvent problems with database update tasks that need to perform cache invalidation, please follow the steps described here: http://oxpedia.org/wiki/index.php?title=AppSuite:Running_a_cluster#Upgrades_of_the_Hazelcast_library. Please also note that session migration is not possible between versions. This usually affects all user sessions that are stored in a distributed map, and will require the users to re-login after the update. Running incompatible versions of Hazelcast within a cluster will result in logentries showing the conflicting node and version information.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you find you are upgrading to a version with breaking Hazelcast changes, please consult the next section [[#Rolling_Upgrade_with_breaking_Hazelcast_upgrade]].&lt;br /&gt;
&lt;br /&gt;
Pre-update:&lt;br /&gt;
&lt;br /&gt;
* Take one middleware node (the upgrade node) out of the HTTP traffic by adjusting the apache mod_proxy tables. We propose a combination of the balancer_manager to do this during runtime without restart, but also update the config files to prevent service restarts of apache to accidentally route sessions to the upgrade node.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node &lt;br /&gt;
* Update packages on the upgrade node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that. You might want to keep the load low on the DBs, to affect production operations as low as possible, and because with this decoupled update tasks approach there is no immediate time pressure. If you want to follow the [[UpdateTasks#How_to_see_all_schemas.3F|limited parallel]] approach, use a small, mild parallelity factor (e.g. 2 or maybe 4 if you know this by far does not saturate your DB platform).&lt;br /&gt;
&lt;br /&gt;
Real Update:&lt;br /&gt;
&lt;br /&gt;
* For one middleware cluster node after each nother:&lt;br /&gt;
** Update packages on that middleware node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
** Verify the node starts its bundles, joins the Hazelcast cluster, log files are clean, the node handles sessions&lt;br /&gt;
* For one frontend node after each other (if you've got separate frontend nodes):&lt;br /&gt;
** Update packages on that frontend node. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Finally, execute &amp;lt;code&amp;gt;touch-appsuite&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;--timestamp&amp;lt;/code&amp;gt; argument as described on the page [[AppSuite:UpdatingOXPackages]]&lt;br /&gt;
* Perform final crosschecks like&lt;br /&gt;
** all middleware nodes joined the Hazelcast cluster&lt;br /&gt;
** all OSGI bundles (which are expected to be running) are running&lt;br /&gt;
** WebUI login is possible&lt;br /&gt;
** Some central functionality tests like sending mails, accessing drive, etc&lt;br /&gt;
&lt;br /&gt;
=== Rolling Upgrade with breaking Hazelcast upgrade ===&lt;br /&gt;
&lt;br /&gt;
Cf [[#Upgrades_of_the_Hazelcast_library]] below.&lt;br /&gt;
&lt;br /&gt;
In principle the steps given in the previous section apply. However the upgrade needs to get the special Hazelcast Upgrade Package installed (e.g. one from &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-76x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-780-782&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-783&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-784&amp;lt;/code&amp;gt;, ...) during execution of the update tasks.&lt;br /&gt;
&lt;br /&gt;
So the pre-update steps look like:&lt;br /&gt;
&lt;br /&gt;
* Take one middleware node (the upgrade node) out of the HTTP traffic by adjusting the apache mod_proxy tables. We propose a combination of the balancer_manager to do this during runtime without restart, but also update the config files to prevent service restarts of apache to accidentally route sessions to the upgrade node.&lt;br /&gt;
* Make sure there are no user sessions left on the upgrade node, and that no new sessions will be routed to that node &lt;br /&gt;
* Update packages on the upgrade node and restart the middleware service there. See [[AppSuite:UpdatingOXPackages]] for details on how to do that.&lt;br /&gt;
* Install the special Hazelcast Upgrade Package on the upgrade node (e.g. one from &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-76x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-780-782&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-783&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;open-xchange-cluster-upgrade-from-784&amp;lt;/code&amp;gt;, ...). Restart the service again.&lt;br /&gt;
* Execute update tasks from that node. See [[UpdateTasks]] for an explanation how to do that. You might want to keep the load low on the DBs, to affect production operations as low as possible, and because with this decoupled update tasks approach there is no immediate time pressure. If you want to follow the [[UpdateTasks#How_to_see_all_schemas.3F|limited parallel]] approach, use a small, mild parallelity factor (e.g. 2 or maybe 4 if you know this by far does not saturate your DB platform).&lt;br /&gt;
&lt;br /&gt;
Note: don't worry if you don't see the upgrade node joining the legacy cluster: the upgrade node will not join the legacy cluster / not be visisble there since the upgrade node will be a so-called &amp;quot;native client&amp;quot; to the legacy cluster, and it will be created on the fly (and subsequently disposed again) for propagating an event. So also on &amp;lt;code&amp;gt;netstat&amp;lt;/code&amp;gt; level the upgrade node will not have visible connections to the legacy cluster (unless for the very short timeframe when an actual even is sent). You can verify the functionality of that package by log lines like&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; Successfully initialzed Hazelcast client: &amp;lt;client-id&amp;gt;&lt;br /&gt;
 Successfully got reference to cache event topic: cacheEvents-3&lt;br /&gt;
 Publishing legacy cache event: &amp;lt;cache-event&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Successfully published legacy cache event, shutting down client after 546ms...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the overly prudent it might be an idea to prepare a special test context with a test user living in its dedicated (test) schema, so you can test the functionality of this mechanis during upgrade first.&lt;br /&gt;
&lt;br /&gt;
After the DB update tasks you can remove the special upgrade package again from the upgrade node.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Real Upgrade&amp;quot; procedure then looks like [[#Rolling_Upgrade_without_breaking_Hazelcast_upgrade|above]].&lt;br /&gt;
&lt;br /&gt;
== Reference Documentation ==&lt;br /&gt;
&lt;br /&gt;
=== Limitations ===&lt;br /&gt;
&lt;br /&gt;
While in most cases a seamless, rolling upgrade of all nodes in the cluster is possible, there may be situations where nodes running a newer version of the Open-Xchange Server are not able to communicate with older nodes in the cluster, i.e. can't access distributed data or consume incompatible event notifications - especially, when the underlying Hazelcast library is part of the update, which does not support this scenario at the moment. In such cases, the release notes will contain corresponding information, so please have a look there before applying an update.&lt;br /&gt;
&lt;br /&gt;
Additionally, there may always be some kind of race conditions during an update, i.e. client requests that can't be completed successfully or internal events not being deliverd to all nodes in the cluster. That's why the following information should only serve as a best-practices guide to minimize the impact of upgrades to the user experience.&lt;br /&gt;
&lt;br /&gt;
=== Upgrading a single Node ===&lt;br /&gt;
&lt;br /&gt;
Upgrading all nodes in the cluster should usually be done sequentially, i.o.w. one node after the other. This means that during the upgrade of one node, the node is temporarily disconnected from the other nodes in the cluster, and will join the cluster again after the update is completed. From the backend perspective, this is as easy as stopping the open-xchange service. other nodes in the cluster will recognize the disconnected node and start to repartition the shared cluster data automatically. But wait a minute - doing so would potentially lead to the webserver not registering the node being stopped immediately, resulting in temporary errors for currently logged in users until they are routed to another machine in the cluster. That's why it's good practice to tell the webserver's load balancer that the node should no longer fulfill incoming requests. The Apache Balancer Manager is an excellent tool for this ([http://httpd.apache.org/docs/2.2/mod/mod_status.html module ''mod_status'']). Look at the screen shot. Every node can be put into a disabled mode. Further requests will the redirected to other nodes in the cluster:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:balancer_manager.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Afterwards, the open-xchange service on the disabled node can be stopped by executing:&lt;br /&gt;
&lt;br /&gt;
 $ /etc/init.d/open-xchange stop&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 $ service open-xchange stop&lt;br /&gt;
&lt;br /&gt;
Now, the node is effectively in maintenance mode and any updates can take place. One could now verify the changed cluster infrastructure by accessing the Hazelcast MBeans either via JMX or the ''showruntimestats -c'' commandline tool (see above for details). There, the shut down node should no longer appear in the 'Member' section (com.hazelcast:type=Member).&lt;br /&gt;
&lt;br /&gt;
When all upgrades are processed, the node open-xchange service can be started again by executing:&lt;br /&gt;
&lt;br /&gt;
 $ /etc/init.d/open-xchange start&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
 $ service open-xchange start&lt;br /&gt;
&lt;br /&gt;
As stated above, depending on the chosen cluster discovery mechanism, it might take some time until the node joins the cluster again. When using static cluster discovery, it will join the existing cluster usually directly during serivce startup, i.o.w. before other depending OSGi services are started. Otherwise, there might also be situations where the node cannot join the cluster directly, for example when there were no mDNS advertisments for other nodes in the cluster received yet. Then, it can take some additional time until the node finally joins the cluster. During startup of the node, you can observe the JMX console or the output of ''showruntimestats -c'' (com.hazelcast:type=Member) of another node in the cluster to verify when the node has joined. &lt;br /&gt;
&lt;br /&gt;
After the node has joined, distributed data is re-partioned automatically, and the node is ready to server incoming requests again - so now the node can finally be enabled again in the load balancer configuration of the webserver. Afterwards, the next node in the cluster can be upgraded using the same procedure, until all nodes were processed.&lt;br /&gt;
&lt;br /&gt;
=== Upgrades of the Hazelcast library ===&lt;br /&gt;
&lt;br /&gt;
In case an upgrade includes a major update of the Hazelcast library, a newly upgraded node will usually not be able to connect to the nodes running the previous version. In this case, volatile cluster data is lost after all nodes in the cluster have been updated, including sessions held in the distributed session storage. As outlined above, the release notes will contain a corresponding warning in such cases.&lt;br /&gt;
&lt;br /&gt;
Besides upgraded nodes not being able to access distributed data of the legacy cluster, this also affects new data not being available in the legacy cluster, which may cause troubles if the updated backend version needs to perform database update tasks. Database update tasks usually operate in a &amp;quot;blocking&amp;quot; way and all contexts associated with the schema being upgraded are disabled temporarily. Since context data itself is being held in caches on potentially each node in the cluster, the affected cache entries are invalidated during the database update. And, since cluster-wide cache invalidations again utilize Hazelcast functionality ([[#Remote Cache Invalidation]]), such invalidations normally won't be propagated to nodes running a previous version of the Hazelcast library.&lt;br /&gt;
&lt;br /&gt;
To work around this specific scenario where an incompatible upgrade of the Hazelcast library needs to be performed along with blocking database update tasks, starting with v7.8.0, a supplementary package is available that explicitly enables the context cache invalidation of nodes running the previous Hazelcast library. This package follows the naming scheme ''open-xchange-cluster-upgrade-from-XXX'' (where XXX representing the version of the legacy version of the Open-Xchange server), and is available in the repositories for the updated server packages. This package should only be installed on the first node of the cluster that is going to be upgraded to the new version, and can be deactivated once the database upgrade tasks were executed successfully. &lt;br /&gt;
&lt;br /&gt;
Once installed, a legacy cluster is discovered based on the available information in the ''hazelcast.properties'' configuration file in case cluster discovery is set to ''static''. If ''multicast'' is used, there's an alternative option to configure at least one of the addresses of the legacy cluster via ''com.openexchange.hazelcast.network.client.nodes''.&lt;br /&gt;
&lt;br /&gt;
As an example, along with the server v7.8.0, a new package named ''open-xchange-cluster-upgrade-from-76x'' can be installed that aids in invalidating cluster server nodes running v7.6.x (which includes the Hazelcast library in version 3.2.4). Using this package, the recommended steps to update an OX cluster from version 7.6.x to version 7.8.0 would be:&lt;br /&gt;
# Pick a node from your cluster that you want to use for executing the database update tasks shipped with the new release&lt;br /&gt;
# Disable this node for incoming HTTP requests in your webserver configuration as described at [[#Upgrading a single Node]]&lt;br /&gt;
# Update the OX packages on this node, additionally install the package ''open-xchange-cluster-upgrade-from-76x''&lt;br /&gt;
# Restart the open-xchange services on this node&lt;br /&gt;
# Trigger the update task executions using the ''runUpdate'' commandline utitlty as described at [[UpdateTasks]]&lt;br /&gt;
# Once they are finished, uninstall the package ''open-xchange-cluster-upgrade-from-76x'' again&lt;br /&gt;
# Restart the open-xchange services on this node&lt;br /&gt;
# Re-enable the node for incoming HTTP requests in your webserver configuration as described at [[#Upgrading a single Node]]&lt;br /&gt;
# Upgrade all other nodes in the cluster as described at [[#Upgrading a single Node]]&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.0 through v7.8.2 (incl.) to v7.8.3 using the package named ''open-xchange-cluster-upgrade-from-780-782'', since v7.8.0 through v7.8.2 (incl.) utilize Hazelcast v3.5.x, while v7.8.3 uses Hazelcast v3.6.4&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.3 to v7.8.4 using the package named ''open-xchange-cluster-upgrade-from-783'', since v7.8.3 utilizes Hazelcast v3.7.1&lt;br /&gt;
&lt;br /&gt;
Same steps apply to upgrading from v7.8.4 to v7.10.0 using the package named ''open-xchange-cluster-upgrade-from-784'', since v7.8.4 utilizes Hazelcast v3.8.1&lt;br /&gt;
&lt;br /&gt;
'''Operations Note:''' The upgraded node will be added as so-called [http://docs.hazelcast.org/docs/2.3/manual/html/ch15.html Native Client] to the legacy Hazelcast Cluster.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Native Client enables you to do all Hazelcast operations without being a member of the cluster.&lt;br /&gt;
[...]&lt;br /&gt;
&lt;br /&gt;
However Native client is not member and relies on one of the cluster members.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This means, the upgraded node will not be visible in the members list of the legacy Hazelcast cluster (&amp;lt;code&amp;gt;showruntimestats -c&amp;lt;/code&amp;gt;). Furthermore, the native client will created and destructed on single context events, with the effect that connections will only be visible in the very moment of such an event. This means effectively that verification of the invalidation mechanis is only possible by actually executing the &amp;lt;code&amp;gt;runupdate&amp;lt;/code&amp;gt; CLT. This should produce log lines like&lt;br /&gt;
&lt;br /&gt;
 Successfully initialzed Hazelcast client: &amp;lt;client-id&amp;gt;&lt;br /&gt;
 Successfully got reference to cache event topic: cacheEvents-3&lt;br /&gt;
 Publishing legacy cache event: &amp;lt;cache-event&amp;gt;&lt;br /&gt;
 Successfully published legacy cache event, shutting down client after 546ms...&lt;br /&gt;
&lt;br /&gt;
Most importantly, you should be able to observe correct functionality (users of affected contexts being logged out). It may be handy to prepare a dedicated schema with just test contexts inside. (How to create this is out of scope here, but hint: use &amp;lt;code&amp;gt;createschema&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;createcontext --schema-name&amp;lt;/code&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
=== Other Considerations ===&lt;br /&gt;
&lt;br /&gt;
* It's always recommended to only upgrade one node after the other, always ensuring that the cluster has formed correctly between each shutdown/startup of a node.&lt;br /&gt;
* Do not stop a node while running the runUpdate script or the associated update task.&lt;br /&gt;
* During the time of such a rolling upgrade of all nodes, we have effectively heterogeneous software versions in the cluster, which potentially might lead to temporary inconsistencies. Therefore, all nodes in the cluster should be updated in one cycle (but still one after the other).&lt;br /&gt;
* Following the above guideline, it's also possible to add or remove nodes dynamically to the cluster, not only when disconnecting a node temporary for updates.&lt;br /&gt;
* In case of trouble, i.e. a node refuses to join the cluster again after restart, consult the logfiles first for any hints about what is causing the problem - both on the disconnected node, and also on other nodes in the network&lt;br /&gt;
* If there are general incompatibilities between two revisions of the Open-Xchange Server that prevent an operation in a cluster (release notes), it's recommended to choose another name for the cluster in ''cluster.properties'' for the nodes with the new version. This will temporary lead to two separate clusters during the rolling upgrade, and finally the old cluster being shut down completely after the last node was updated to the new version. While distributed data can't be migrated from one server version to another in this scenario due to incompatibilities, the uptime of the system itself is not affected, since the nodes in the new cluster are able to serve new incoming requests directly.&lt;br /&gt;
* When updating only UI plugins without also updating to a new version of the core UI, you also need to perform the additional step from [[AppSuite:UpdatingOXPackages#Updating_UI_plugins|Updating UI plugins]].&lt;br /&gt;
&lt;br /&gt;
[[Category: AppSuite]] [[Category: Administration]] [[Category: Cluster]]&lt;/div&gt;</summary>
		<author><name>Dominik.epple</name></author>
	</entry>
</feed>