Server and database configuration best practices

November 14, 2023

Installation modes

The application can be installed in two different modes, the choice is done through the installer or can be changed later in the file jahia.properties

Development mode: in this mode the Studio is available and several background observers are in charge of looking for changes on source files in order to react instantly to those changes, which is convenient when developing.

Production mode: in this mode observers are disabled or run on a slower pace, reducing the load on the server, and the Studio is not available to avoid risks of live changes that could break the site(s) in case of misusage or code error. Production mode is not available for Community Edition.

A typical installation with the Enterprise Edition contains one server in production mode accessible to visitors and one environment in development mode. Changes are done on the development server, then pushed on the production server - sometimes on a test server first - to ensure only secure developments are deployed on the public server.

Database: MySQL tips

Database configuration

Jahia uses BLOBs to store its data. Default MySQL installation may allow small packets only - check that the max_allowed_packet value is set to a value large enough :
[mysqld]
...
max_allowed_packet = 100M
...
Jahia is using InnoDB for its database engine on MySQL so be sure that you have configured your MySQL for InnoDB. Here some default configuration for your database to be put in your my.cnf or my.ini file.
#
# * InnoDB
#
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!
#

# You can write your other MySQL server options here
# ...
# Data files must be able to hold your data and indexes.
# Make sure that you have enough free disk space.
innodb_data_file_path = ibdata1:100M:autoextend
#
# Can be set to 70-80% of memory for dedicated InnoDB-Only MySQL
innodb_buffer_pool_size=1024M
innodb_additional_mem_pool_size=24M
#
# Set the log file size to about 25% of the buffer pool size
innodb_log_file_size=256M
innodb_log_buffer_size=64M
#
innodb_flush_log_at_trx_commit=1

For advanced users, there is a useful tool that you can use to tune your database at https://github.com/major/MySQLTuner-perl. MySQLTuner is a script written in Perl that will assist you with your MySQL configuration and make recommendations for increased performance and stability.

MySQL on Mac OS X

Please note that for MySQL versions from 5.5.9 to 5.5.12 on MacOSX, you must set the value of lower_case_table_names to 1 (http://bugs.mysql.com/bug.php?id=60309).

MySQL on Unix

According to (http://dev.mysql.com/doc/refman/5.0/en/innodb-tuning.html) in some versions of GNU/Linux and Unix, flushing files to disk with the Unix fsync() call (which InnoDB uses by default) and other similar methods is surprisingly slow. If you are dissatisfied with database write performance, you might try setting the innodb_flush_method parameter to O_DSYNC. The O_DSYNC flush method seems to perform slower on most systems, but yours might not be one of them.

Support of UTF-8 4 byte characters with MySQL

If in you project you require to use UTF-8 4-byte characters in the JCR node names you need to enforce the server character set to utf8mb4 instead of utf8 and use the corresponding collation (utf8mb4_general_ci):
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
 The characterEncoding=UTF-8 parameter should also be removed from the JDBC connection URL, i.e. instead of the default:
jdbc:mysql://localhost/jahia?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false
the following one should be used:
jdbc:mysql://localhost/jahia?useUnicode=true&useServerPrepStmts=false
Note, please, this requirement is only applicable to JCR node names only. There is no issue at all with the node property values (content), having UTF-8 4 byte characters.

Apache HTTP server

Use an Apache HTTP Server as a frontal

For URL rewriting we suggest that you use an Apache HTTP Server with the http proxy modules activated (proxy, proxy_http) and rewrite module (rewrite).

First, you will have to modify the WEB-INF/urlrewrite.xml file inside JAHIA. Uncomment the following lines to activate rewriting of URLs.

<!--
<outbound-rule>
    <from>/jahia/cms/render/live/en/sites/mySite/([a-zA-Z_0-9/\.]+html)$</from>
    <to last="true">/$1</to>
</outbound-rule>
<outbound-rule>
    <from>/jahia/cms/render/live/en/users/([a-zA-Z_0-9/\.]+html)$</from>
    <to last="true">/users/$1</to>
</outbound-rule>
-->

Replace /jahia by your context name (nothing if the context is ROOT). This rules will only rewrite URLs in live mode.

In Apache HTTP server you need to declare a virtual host for your website like the example below :

<VirtualHost *:80>
        Options +FollowSymlinks
        RewriteEngine on
        RewriteCond %{REQUEST_URI} ^/jahia/cms/render/live.*$
        RewriteRule ^/jahia/cms/render/live/([a-zA-Z_0-9/\.]+html)$ http://localhost:8080/jahia/cms/render/live/$1 [P,L]
        RewriteRule ^/users/([a-zA-Z_0-9/\.]+html)$ http://localhost:8080/jahia/cms/render/live/en/users/$1 [P,L]
        RewriteRule ^/([a-zA-Z_0-9/\.]+html)$ http://localhost:8080/jahia/cms/render/live/en/sites/mySite/$1 [P,L]
        RewriteLog "/var/log/apache2/rewrite.log"
        RewriteLogLevel 3
    ProxyRequests Off
    ProxyPreservehost on
    ServerName example.domain.com
    ProxyPass  /sitemap.xml http://localhost:8080/jahia/cms/render/live/en/sites/mySite/home.sitemap.xml
    ProxyPassReverse /sitemap.xml http://localhost:8080/jahia/cms/render/live/en/sites/mySite/home.sitemap.xml
        ProxyPass  / http://localhost:8080/
    ProxyPassReverse / http://localhost:8080/
    <Proxy>
        Order Allow,Deny
        Allow from all
    </Proxy>
</VirtualHost>

This virtual host will only handle live mode and you can define another one for edit/preview mode

<VirtualHost *:80>
        Options +FollowSymlinks
        RewriteEngine on
        RewriteCond %{REQUEST_URI} ^/jahia/cms/edit/default.*$
        RewriteRule ^/jahia/cms/edit/default/([a-zA-Z_0-9/\.]+html)$ http://localhost:8080/jahia/cms/edit/default/$1 [P,L]
        RewriteCond %{REQUEST_URI} ^/jahia/cms/render/default.*$
        RewriteRule ^/jahia/cms/render/default/([a-zA-Z_0-9/\.]+html)$ http://localhost:8080/jahia/cms/render/default/$1 [P,L]
        RewriteCond %{REQUEST_URI} !^/jahia/.*$
        RewriteRule ^/([a-zA-Z_0-9/\.]+html)$ http://localhost:8080/jahia/cms/edit/default/en/sites/mySite/$1 [P,L]
        RewriteLog "/var/log/apache2/rewrite.log"
        RewriteLogLevel 3
        ProxyRequests Off
        ProxyPreservehost on
        ServerName edit.tata.mondomaine.com
        ProxyPass  / http://localhost:8080/
        ProxyPassReverse / http://localhost:8080/
        <Proxy>
            Order Allow,Deny
            Allow from all
        </Proxy>
</VirtualHost>

In Tomcat, you will have to modify the connector in the file "TOMCAT_HOME/conf/server.xml" to reflect the proxy values (attributes proxyName, proxyPort and scheme).

You'll find below an example when the website is accessed with the url : https://www.example.domain.com:443

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               maxThreads="300" acceptCount="100"
               enableLookups="false"
               URIEncoding="UTF-8"
               compression="on"
               proxyName="www.example.domain.com"
               proxyPort="443"
               redirectPort="443"
               scheme="https"
               compressableMimeType="text/plain,text/html,text/xml,text/css,text/javascript,application/x-javascript,application/javascript" />

Production tips

  • Fine tune the JVM. As with all Java applications, the tuning of your JVM will have a big impact on your performances, choose the right GC, the right amount of memory,etc. See our fine tuning guide for more Jahia 6.6 specific information.
  • Fine tune the underlying connections between Jahia 6.6 and the DB, monitor regularly your database performances, log all slow queries so that you can find what need to be improved on the DB side. See our fine tuning guide for more Jahia 6.6 specific information.
  • Deactivate profiler logs, turn the following category to a higher level than DEBUG, for example, ERROR:
<category name="profilerLoggingService" additivity="false">
    <priority value="ERROR"/>
    <appender-ref ref="profilerLogs"/>
</category>
  • Reduce the general level of the ROOT category to at least WARN level (ERROR and FATAL having even less impact on performance), if you have some issue then you can go back to INFO or DEBUG level if needed or asked by our customer services. Anyway, Jahia 6.6 will log all your errors in a separate file for each of them so if needed you can at least provide this file to our customer services.
  • When deploying new modules remember to use the deployModule script :
deployModule module1.war [module2.war ...] tomcat/webapp/ROOT

From dev to production

Web project from development to production

Create a project with the maven archetype :

mvn archetype:generate -Dfilter=org.jahia.archetypes:

(do not forget the colon at the end of the filter value).

Full web projects in one place (templates and modules)

Choose jahia-templatesSet-archetype (4)

If you want to split your templates and your functional modules then first create a template project (5) then you will create modules projects as needed.

Create a template project :

  • artifactId = mycustomtemplateset
  • jahiaPackageVersion = (name of the jahia version you want to use) (for example 6.6.0.0)
  • moduleName = myCustomTemplateSet

Content of your project :

mycustomtemplateset
+── src
    +── main
    +   +── import
    +   +── java
    +   +── resources
    +   │   +── META-INF
    +   +── webapp
    +       +── META-INF
    +       │   +── spring
    +       +── css
    +       +── icons
    +       +── img
    +       +── javascript
    +       +── jnt_template
    +       │   +── html
    +       +── resources
    +       +── scripts
    +── site
        +── apt

In src/main/webapp/resources rename __resourceBundleName__.properties with moduleName.properties (ex:myCustomTemplateSet.properties). Note that spaces in moduleName will be removed to be used for the resource bundle file. So if your moduleName was "My Custom Template Set" the properties file should be MyCustomTemplateSet.properties

Now make sure you jahia is running

Build and deploy your newly created template set using maven

mvn install jahia:deploy

inside your Jahia you should see something like this on the console :

2012-01-11 11:32:03,223: INFO  [TemplatePackageDeployer] - Start deploying new module package 'myCustomTemplateSet' version=1.0-SNAPSHOT
2012-01-11 11:32:03,230: INFO  [TemplatePackageDeployer] - Deploying JARs for module myCustomTemplateSet
2012-01-11 11:32:03,390: INFO  [JackrabbitStoreProvider] - Custom node types registered for myCustomTemplateSet in 130 ms
2012-01-11 11:32:03,400: INFO  [TemplatePackageRegistry] - Registered myCustomTemplateSet version=1.0-SNAPSHOT
2012-01-11 11:32:03,415: INFO  [TemplatePackageApplicationContextLoader] - Reloading Spring application context for Jahia modules
2012-01-11 11:32:04,527: INFO  [JobSchedulingBean] - Deleting job Maintenance.VisibilityActionPurgeJob
2012-01-11 11:32:04,562: INFO  [JobSchedulingBean] - Scheduling persistent job Maintenance.VisibilityActionPurgeJob
2012-01-11 11:32:04,585: INFO  [JobSchedulingBean] - Deleting job SitemapJob.SitemapJob
2012-01-11 11:32:04,585: INFO  [JobSchedulingBean] - Scheduling RAM job SitemapJob.SitemapJob
2012-01-11 11:32:04,587: INFO  [TemplatePackageApplicationContextLoader] - Jahia modules application context reload completed in 1172 ms
2012-01-11 11:32:04,639: INFO  [TemplatePackageDeployer] - Checking for missing module nodes and initializing 0 of them took 52 ms
2012-01-11 11:32:05,174: INFO  [RulesListener] - Rules executed for live [/templateSets/mycustomtemplateset, /templateSets/mycustomtemplateset/j:wcagCompliance] in 1ms
2012-01-11 11:32:05,441: INFO  [RulesListener] - Rules executed for live [/templateSets/mycustomtemplateset/jcr:mixinTypes, /templateSets/mycustomtemplateset/priority, /templateSets/mycustomtemplateset/changefreq] in 0ms
2012-01-11 11:32:05,479: INFO  [RulesListener] - Rules executed for default [/templateSets/mycustomtemplateset/templates/contents, /templateSets/mycustomtemplateset/templates/files, /templateSets/mycustomtemplateset/contents] ... and 3 other nodes in 116ms
2012-01-11 11:32:05,492: INFO  [TemplatePackageDeployer] - Starting import for the module package 'myCustomTemplateSet' including: [META-INF/import.zip]
2012-01-11 11:32:05,521: INFO  [TemplatePackageDeployer] - ... importing /home/user1/Ent-Jahia_xCM_v6.6/tomcat/webapps/ROOT/modules/mycustomtemplateset/META-INF/import.zip into /
2012-01-11 11:32:05,524: ERROR [DocumentViewImportHandler] - Couldn't find definition for property j:displayInMenu
2012-01-11 11:32:05,857: INFO  [RulesListener] - Rules executed for live [/templateSets/mycustomtemplateset/j:installedModules, /templateSets/mycustomtemplateset/j:siteType] in 0ms
2012-01-11 11:32:05,918: INFO  [RulesListener] - Rules executed for default [deleted /templateSets, deleted /templateSets/mycustomtemplateset/templates/files, deleted /templateSets/mycustomtemplateset/templates/contents] ... and 23 other nodes in 20ms
2012-01-11 11:32:06,025: INFO  [RulesListener] - Rules executed for live [/templateSets/mycustomtemplateset/j:installedModules, /templateSets/mycustomtemplateset/j:title, /templateSets/mycustomtemplateset/j:dependencies] in 1ms
2012-01-11 11:32:06,062: INFO  [RulesListener] - Rules executed for default [/templateSets/mycustomtemplateset/j:siteType, /templateSets/mycustomtemplateset/j:installedModules, /templateSets/mycustomtemplateset/j:title] ... and 1 other nodes in 1ms
2012-01-11 11:32:06,063: INFO  [TemplatePackageDeployer] - ... finished initial import for module package 'myCustomTemplateSet'.
2012-01-11 11:32:06,063: INFO  [ComponentRegistry] - Start registering UI droppable components...

Now connect to your Jahia instance at http://127.0.0.1:8080/start and modify your template set using the studio, add some images/css/javascript as needed see the Jahia Template Development Documentation for more information about this.

Once your template set looks near its done, export it, update your repository.xml file with the new content.

To export it, select "Export" from Export the top menu

export.png

And open the xml file

export2.png

Copy the content of the xml file to the ./src/main/import/repository.xml file

Create a site with your template set (go to the administration for that).

From now on you can update your template (if modifying files you need to redeploy your template set) and/or create content on your site.

When your site is ready to be exported go to administration export the whole site, you will get a zip containing everything to import your site.

You can now deploy your templates and all necessary modules on another server and then import this file when creating a new site.

Or you can create another project and store your site in it, then use maven to package it and then deploy it into jahia. Here how to achieve that :

  • Create a new directory at the same level you create your mycustomtemplateset project call it mycustomsite
  • Now create a pom.xml file like this one at the root of your project :
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <groupId>org.jahia.prepackagedsites</groupId>
            <artifactId>prepackagedSites</artifactId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
        <artifactId>mycustomsite</artifactId>
        <version>1.0-SNAPSHOT</version>
        <name>My Custom Site</name>
        <packaging>pom</packaging>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>ACME</id>
                            <configuration>
                                <descriptors>
                                    <descriptor>src/main/assembly/mycustomsite.xml</descriptor>
                                </descriptors>
                                <attach>false</attach>
                                <finalName>myCustomSite</finalName>
                                <appendAssemblyId>false</appendAssemblyId>
                            </configuration>
                            <phase>validate</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>users</id>
                            <configuration>
                                <descriptors>
                                    <descriptor>src/main/assembly/users.xml</descriptor>
                                </descriptors>
                                <attach>false</attach>
                                <finalName>users</finalName>
                                <appendAssemblyId>false</appendAssemblyId>
                            </configuration>
                            <phase>validate</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>systemsite</id>
                            <configuration>
                                <descriptors>
                                    <descriptor>src/main/assembly/systemsite.xml</descriptor>
                                </descriptors>
                                <attach>false</attach>
                                <finalName>systemsite</finalName>
                                <appendAssemblyId>false</appendAssemblyId>
                            </configuration>
                            <phase>validate</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>root</id>
                            <configuration>
                                <descriptors>
                                    <descriptor>src/main/assembly/root.xml</descriptor>
                                </descriptors>
                                <appendAssemblyId>false</appendAssemblyId>
                            </configuration>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
  • Now create folders src/main, then expand your site zip file inside src/main, you will have several zip files and one property file.
  • Copy the property file in a folder named root
  • Extract the content of systemsite inside a folder named system site
  • Extract the content of users in src/main (users.zip contains a folder already named users)
  • Now we will create the assembly files that will repackage everything together :
    • in src/main/assembly create mycustomsite.xml as this one:
      <assembly>
          <id>ACME</id>
          <includeBaseDirectory>false</includeBaseDirectory>
          <formats>
              <format>zip</format>
          </formats>
          <fileSets>
              <fileSet>
                  <directory>${basedir}/src/main/myCustomSite</directory>
                  <includes>
                      <include>**/*</include>
                  </includes>
                  <outputDirectory></outputDirectory>
              </fileSet>
          </fileSets>
      </assembly>
    • in src/main/assembly create systemsite.xml as this one:
      <assembly>
          <id>systemside</id>
          <includeBaseDirectory>false</includeBaseDirectory>
          <formats>
              <format>zip</format>
          </formats>
          <fileSets>
              <fileSet>
                  <directory>${basedir}/src/main/systemsite</directory>
                  <includes>
                      <include>**/*</include>
                  </includes>
                  <outputDirectory></outputDirectory>
              </fileSet>
          </fileSets>
      </assembly>
    • in src/main/assembly create users.xml as this one:
      <assembly>
          <id>users</id>
          <includeBaseDirectory>false</includeBaseDirectory>
          <formats>
              <format>zip</format>
          </formats>
          <fileSets>
              <fileSet>
                  <directory>${basedir}/src/main/users</directory>
                  <includes>
                      <include>**/*</include>
                  </includes>
                  <outputDirectory></outputDirectory>
              </fileSet>
          </fileSets>
      </assembly>
    • in src/main/assembly create root.xml as this one:
      <assembly>
          <id>root</id>
          <includeBaseDirectory>false</includeBaseDirectory>
          <formats>
              <format>zip</format>
          </formats>
          <fileSets>
              <fileSet>
                  <directory>${basedir}/src/main/root</directory>
                  <includes>
                      <include>**</include>
                  </includes>
                  <outputDirectory></outputDirectory>
              </fileSet>
              <fileSet>
                  <directory>${basedir}/target</directory>
                  <includes>
                      <include>myCustomSite.zip</include>
                  </includes>
                  <outputDirectory></outputDirectory>
              </fileSet>
              <fileSet>
                  <directory>${basedir}/target</directory>
                  <includes>
                      <include>users.zip</include>
                  </includes>
                  <outputDirectory></outputDirectory>
              </fileSet>
              <fileSet>
                  <directory>${basedir}/target</directory>
                  <includes>
                      <include>systemsite.zip</include>
                  </includes>
                  <outputDirectory></outputDirectory>
              </fileSet>
          </fileSets>
      </assembly>

Now your mycustomsite folder should like something like that :

   |-src
   |---main
   |-----assembly
   |-----myCustomSite
   |-------content
   |-----root
   |-----systemsite
   |-----users
   |-------content

Now install a production env on your server, do not start your jahia yet.

Deploy all necessary modules you might need for your project especially your mycustomtemplateset war file using the deployModule.sh (or deployModule.bat) script provided by Jahia :

 deployModule module1.war [module2.war ...] tomcat/webapp/ROOT

Inside Ent-Jahia_xCM_v6.6.0.0/tomcat/webapps/ROOT/WEB-INF/var create if missing the following folder : prepackagedSites

Then copy mycustomsite/target/mycustomsite-1.0-SNAPSHOT.zip inside this prepackagedSites folder

Now start your jahia, import your site and enjoy

From now on you can deploy a new version of your templateset inside the shared module, then you will have to go to your site administration to deploy your template on your site as there is no studio on production env.

Of roles and permissions :

If ever you need some particular permissions and/or roles on your project keep in mind that those are imported with their own file, they are not part of an export and so need to be placed alongside your repository.xml file in your import folder.

|-content
|--permissions.xml
|--repository.xml
|--roles.xml

For example look at the JahiaApp-Wiki

Git: Windows issues

Git: long path issue on Microsoft Window platform

Git on Windows does not supports paths, longer than 260 characters (Windows' MAX_PATH): Git-cannot-create-a-filedirectory-with-a-long-path
This is a known technical limitation on Windows.
The latest released version of msysgit - Git for Windows (Git-1.9.0-preview20140217.exe) introduced support for long paths (issue #52). Assuming only that the "core.longpaths" config entry is set to true, i.e.:
git config --global --add core.longpaths true

Tomcat configuration

Tomcat : connectors configuration

Tomcat supports NIO connectors instead of HTTP and AJP protocol, which allows a better use of resources. You can switch to this configuration by editing the tomcat.xml file.

HTTP NIO Connector

In the HTTP connector section (port 8080), replace : 
protocol="HTTP/1.1"
with :
protocol="org.apache.coyote.http11.Http11NioProtocol"
You can also do the same thing for HTTPS connector (port 8443) if you are using SSL connections.
Additional configuration parameters can be found on tomcat website : 
http://tomcat.apache.org/tomcat-7.0-doc/config/http.html#NIO_specific_configuration

AJP NIO Connector

In the AJP connector section (port 8009), replace : 
protocol="AJP/1.3"
with :
protocol="org.apache.coyote.ajp.AjpNioProtocol"
Additional configuration parameters can be found on tomcat website : 
http://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html#NIO_specific_configuration

Native Connector

For even better tomcat performances, it is recommended to use native libraries, as explained in : 
http://tomcat.apache.org/tomcat-7.0-doc/apr.html
Once the native library is installed and available as a shared library, it will be automatically used by tomcat, without the need to change the configuration. At startup, you should see a message like :
INFO: Loaded APR based Apache Tomcat Native library x.x.x using APR version x.x.x.