Tomcat Installation

Version 66.1 by Thomas Mortagne on 2022/11/18

Installation Steps

  • Download and install Tomcat 8+. There are plenty of ways to install Tomcat, refer to the Tomcat site for more information. Let's call TOMCAT_HOME the directory where it's installed.

    Using Tomcat 10 is not recommended right now since it moved to the incompatible Jakarta EE 9 API. See Apache Tomcat migration tool for Jakarta EE for mode details.

  • Make sure you give enough memory to Java since by default Tomcat is not configured with enough memory for XWiki.
  • Extract the XWiki WAR into a directory named xwiki in TOMCAT_HOME/webapps/
  • Open TOMCAT_HOME/webapps/xwiki/WEB-INF/xwiki.properties files and configure a permanent directory
  • Start Tomcat
  • When Tomcat has opened go to your wiki by accessing http://localhost:8080/xwiki/bin/view/Main/
  • NOTE - if you have issues with maximum cache size - In your $CATALINA_BASE/conf/context.xml add the following content before </Context>:
    <Resources cachingAllowed="true" cacheMaxSize="100000" ></Resources>

Activate headless mode

If you're operating XWiki on a Linux server with no X11 libraries installed you have to enable headless mode for your Tomcat installation. Sometimes this is also needed on Windows platforms. Typical exceptions are:

  • Exception: Could not initialize class sun.awt.X11.XToolkit
  • java.lang.InternalError: Can't connect to X11 window server using 'localhost:10.0' as the value of the DISPLAY variable
  • On Linux create a file /TOMCAT_HOME/bin/setenv.sh and insert the following code:
    #!/bin/sh
    export JAVA_OPTS="${JAVA_OPTS} -Djava.awt.headless=true"
  • On Windows create a file /TOMCAT_HOME/bin/setenv.bat and insert the following code:
    set JAVA_OPTS=%JAVA_OPTS% -Djava.awt.headless=true
  • When running as a Windows service the setenv.bat is not working. See registry HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Procrun 2.0\FOOBAR\Parameters\Java for similar settings.

Optional configuration

  • Edit your conf/server.xml to enable gzip compression: <Connector port="8080" ... compression="on" compressionMinSize="2048" compressibleMimeType="text/html,text/xml,text/css,text/javascript,application/x-javascript"></Connector>
  • If you want to modify the port on which Tomcat will run, edit TOMCAT_HOME/conf/server.xml/. Search for 8080 (sometimes 8180 if you are under Linux) and replace with the port value you wish to use.
  • It is possible to setup a Tomcat Java Server as a UNIX Daemon - JSVC. Just follow these instructions. The only reason to make Tomcat a daemon is to make it runnable on the 80th port, which can be replaced by using NginX as a proxy on the 80th port and then forwarding to Tomcat to the 8080th port.

Policy configuration

For those who activate the security manager for Tomcat, add this portion of code to the end of your conf/catalina.policy file from your Tomcat installation. You can adapt the code for the available installations of OpenOffice/LibreOffice on your server and for different databases :

grant codeBase "file:${catalina.base}/webapps/xwiki/WEB-INF/lib/-" {
 // for mySQL connection
 permission java.net.SocketPermission "127.0.0.1:3306", "connect,resolve";

 // XWiki must have access to all properties in read/write
 permission java.util.PropertyPermission "*", "read, write";

 // Generic detected permissions
 permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
 permission java.lang.RuntimePermission "createClassLoader";
 permission java.lang.RuntimePermission "setContextClassLoader";
 permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.loader";
 permission java.lang.RuntimePermission "accessDeclaredMembers";
 permission java.lang.RuntimePermission "getenv.ProgramFiles";
 permission java.lang.RuntimePermission "getenv.APPDATA";
 permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect";
 permission java.lang.RuntimePermission "getClassLoader";
 permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.connector";
 permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.threads";
 permission java.lang.RuntimePermission "reflectionFactoryAccess";
 permission java.lang.RuntimePermission "accessClassInPackage.com.sun.jmx.interceptor";
 permission java.lang.RuntimePermission "accessClassInPackage.com.sun.jmx.mbeanserver";
 permission java.lang.RuntimePermission "modifyThread";
 permission java.lang.RuntimePermission "getProtectionDomain";

 // JAXB permissions
 permission javax.xml.bind.JAXBPermission "setDatatypeConverter";

 // Serialization related permissions
 permission java.io.SerializablePermission "allowSerializationReflection";
 permission java.io.SerializablePermission "creator";
 permission java.io.SerializablePermission "enableSubclassImplementation";

 // Internal resources access permissions
 permission java.io.FilePermission "synonyms.txt", "read";
 permission java.io.FilePermission "lang/synonyms_en.txt", "read";
 permission java.io.FilePermission "quartz.properties", "read";
 permission java.io.FilePermission "/templates/-", "read";
 permission java.io.FilePermission "/skins/-", "read";
 permission java.io.FilePermission "/resources/-", "read";

 // MBean related permissions
 permission javax.management.MBeanServerPermission "createMBeanServer";
 permission javax.management.MBeanPermission "*", "registerMBean";
 permission javax.management.MBeanPermission "*", "unregisterMBean";
 permission javax.management.MBeanTrustPermission "register";
 permission javax.management.MBeanPermission "-#-[-]", "queryNames";
 permission javax.management.MBeanServerPermission "findMBeanServer";

 // LibreOffice/OpenOffice related permissions
 permission java.io.FilePermission "/opt/openoffice.org3/program/soffice.bin", "read";
 permission java.io.FilePermission "/opt/libreoffice/program/soffice.bin", "read";
 permission java.io.FilePermission "/usr/lib/openoffice/program/soffice.bin", "read";
 permission java.io.FilePermission "/usr/lib/libreoffice/program/soffice.bin", "read";

 // Allow file storage directory reading - for directory and everything underneath
 // This is dependent on the setting of environment.permanentDirectory in xwiki.properties
 permission java.io.FilePermission "${catalina.base}${file.separator}xwikidata${file.separator}", "read,write,delete";
 permission java.io.FilePermission "${catalina.base}${file.separator}xwikidata${file.separator}-", "read,write,delete";

 // Allow file storage directory reading - temporary directory and everything underneath
 // This is dependent on the setting of environment.temporaryDirectory in xwiki.properties.
 permission java.io.FilePermission "${catalina.base}${file.separator}temp${file.separator}", "read,write,delete";
 permission java.io.FilePermission "${catalina.base}${file.separator}temp${file.separator}-", "read,write,delete";
};

Please note that this policy configuration file has been tested on CentOS 5.9 with Sun JDK 1.7.0u21 on Tomcat 7.0.40 with XWiki 5.0.1 installed.

Using Nginx as a reverse-proxy for Tomcat (http/https)

For a variety of reasons, it is not ideal to allow users to connect directly to tomcat. A popular choice for a reverse-proxy web server is Nginx. These instructions will walk through a very basic deployment of nginx acting as a reverse-proxy for the tomcat XWiki application. 

After a typical XWiki installation XWiki will be running on http://localhost:8080/xwiki. Ultimately we will want to access XWiki via http://mydomain.com on a standard http (80) or https (443) port. To accomplish this for unsecure http traffic, the following basic config file gets us started.

http (unsecure)

  • create this file /etc/nginx/conf.d/tomcat.conf
  • put the following code inside:
    server {
       listen       80;
       server_name  mydomain.com;

        # Normally root should not be accessed, however, root should not serve files that might compromise the security of your server.
       root /var/www/html;

        # Configuration to avoid Request Entity too large error 413
       client_max_body_size 0;
     
       location / {
            # All "root" requests will have /xwiki appended AND redirected to mydomain.com
           rewrite ^ $scheme://$server_name/xwiki$request_uri? permanent;
        }

       location ^~ /xwiki {
           # If path starts with /xwiki - then redirect to backend: XWiki application in Tomcat
           # Read more about proxy_pass: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
          proxy_pass http://localhost:8080;
          proxy_set_header        X-Real-IP $remote_addr;
          proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header        Host $http_host;
          proxy_set_header        X-Forwarded-Proto $scheme;
        }
    }
  • restart nginx

Now all http://mydomain.com/* requests will lead to the XWiki application. Please note that these settings are basic. For more flexible solutions please refer to the Nginx documentation

https (secure)

There are many guides on how to create a secure configuration of nginx. To get started:

The following config assumes you are using LetsEncrypt and that your XWiki is hosted on http://localhost:8080/. This config will redirect all unsecure requests to https:// and set the correct proxy headers for a secure nginx+tomcat setup.

First, you will need to add the following config to tomcat's server.xml (located at /etc/tomcat8/server.xml on Ubuntu 16.04). The first line should already be in the file, I include it to give you something to search for (that line is located on line 108 in the Ubuntu 16.04 tomcat8 package). This will help tomcat find your proxy headers.

<Engine name="Catalina" defaultHost="localhost">
 <Valve className="org.apache.catalina.valves.RemoteIpValve"
   internalProxies="127\.0\.[0-1]\.1"
   remoteIpHeader="x-forwarded-for"
   requestAttributesEnabled="true"
   protocolHeader="x-forwarded-proto"
   protocolHeaderHttpsValue="https"></Valve>

Next, add the following nginx config file to your nginx config folder, replacing wiki.yourdomain.com with your actual domain info:

server {
   listen      80;
   server_name wiki.yourdomain.com;

   location ~ /.well-known {
       allow all;
    }

   rewrite     ^   https://$server_name$request_uri? permanent;

   access_log /var/log/nginx-xwiki/access.log;
   error_log /var/log/nginx-xwiki/error.log;

}

server {
   listen      443;
   server_name wiki.yourdomain.com;

   root /var/www/html;

    # Configuration to avoid Request Entity too large error 413
   client_max_body_size 0;

   ssl on;
   ssl_certificate /etc/letsencrypt/live/wiki.yourdomain.com/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/wiki.yourdomain.com/privkey.pem;

   access_log /var/log/nginx-xwiki/access_ssl.log;
   error_log /var/log/nginx-xwiki/error_ssl.log;

   location / {
       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_set_header X-Scheme $scheme;
       proxy_redirect off;
       if (!-f $request_filename) {
           proxy_pass http://127.0.0.1:8080;
           break;
        }
    }

   location ~ /.well-known {
       allow all;
    }
 }

For more background on this config, see the discussion on this ticket: XWIKI-13963.

Proxying and tunnels

This proxy methods brings remote connections to local connection. This is complementary to SSH-tunneling which is easily done on port 8080 and can be used to test development servers.

For example, if you are running an XWiki on port 80 on your laptop while running the NGinx (or Apache) on a server where it is accessible as https://wiki.yourdomain.com, you can make your XWiki acessible with this URL:

  • First make sure that the port 8080 is not in use: You can proof this with ssh server wget -O - https://127.0.0.1:8080/ which should display the error message Connection refused. If not, something is running there and it should be stopped.
  • You can then create the tunnel with the following ssh -R8080:127.0.0.1:8080 server. This tells the server that incoming ("R"emote) connections on port 8080 on the server are to be tunnelled to the local (laptop) port 8080. This method has the advantage that the laptop (typically using a dynamic address) invokes the SSH where as a proxy configured on the server to proxy to the laptop would need to know the address of the laptop.

Configuring tomcat for https

Although allowing users to directly connect to tomcat is not recommended, for a variety of reasons it may be desirable to configure tomcat to serve pages over an https connection.If using another server as a HTTPS proxy (such as Nginx or Apache httpd), follow instruction below to avoid unexpected error (such as "failed to lock page").

  • If using HTTPS for accessing XWiki, several modifications have to be made to ensure proper functionality. Since urls are generated from relative path (/xwiki/bin/show/Space/Page), Tomcat has to know which protocol to use, otherwise JSON requests with redirect fails (attachment uploads, extension updating, etc.)
  • Modify connector (in server.xml) to <Connector port="8080" ... secure="true" scheme="https" ></Connector>
  • Modify host (in server.xml) and add Remote Ip Valve <Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="x-forwarded-for" protocolHeader="x-forwarded-proto" ></Valve> (only needed if using another server for HTTPS)

Set X-Forwarded-For and X-Forwarded-Proto headers on HTTPS guard server(on which Apache httpd or Nginx runs)!

Recommendations

Default encoding

XWiki strives to not be impacted by the default encoding, but it's still possible to have bugs or simply mistakes in extensions or tools used by XWiki (database connectors, etc.) so it's highly recommended to make sure Tomcat is started with utf8 as default encoding. If you use a Linux package of Tomcat this is generally set by default, but it might not always be the case. For that, make sure you have -Dfile.encoding=utf8 in the Java command line which starts Tomcat.

Troubleshooting

Out Of Memory Error

General Memory Settings

When you run XWiki in Tomcat with the default settings, you'll probably get an Out Of Memory error (java.lang.OutOfMemoryError: Java heap space or java.lang.OutOfMemoryError: PermGen space) since the default Tomcat memory settings are not enough for XWiki Memory Requirements. You'll need to allocate more memory to the JVM. 

One easy solution to configure Tomcat's memory is to create a setenv.sh file (or setenv.bat on Windows) in [TOMCAT_HOME]/bin/ (where [TOMCAT_HOME] is where you've installed Tomcat) and inside this file add the following (adjust the memory values according to the XWiki Memory Requirements). For example:

CATALINA_OPTS="-Xmx1024m -XX:MaxPermSize=192m"

On most Linux distributions, this can also be achieved in /etc/tomcatX/tomcatX.conf or /etc/conf.d/tomcatX.conf (where X is the version of Tomcat installed).

On Windows, if you are running Tomcat as a service then defining CATALINA_OPTS will not help. There is an utility provided in the bin folder of your Tomcat installation (for example for Tomcat 5.x on Windows it's called tomcat5w.exe). It's a GUI tool which can be used to set various options including the heap size.

Max number of threads

On some Debian 10 installations there can be a limitation of the max number of threads for services started with systemd (and tomcat9 is such a service), what can force problems with OOM Errors: Out Of Memory error (java.lang.OutOfMemoryError: unable to create native thread)

If you have such messages in the catalina.out check your default limitations of the systemd with the command

> systemctl show --property DefaultTasksMax

For XWiki a value of about 100 is too low. Depending on the number of parallel users and sub wikis, this value should be larger. A value of about 512 should be sufficient. 

Changing the parameter DefaultTasksMax in /etc/systemd/system.conf to a larger value, restarting the system-daemon and tomcat9, should solve the problem.

> systemctl daemon-reload
> systemctl restart tomcat9

If the problem is not fixed with these changes, check the number of currently used threads by tomcat9 with the command

> ps -elfT | grep tomcat9| wc -l

If the value is very near to the configured DefaultTasksMax, you can try to increase it to an appropriate value.

Java Security Manager

By default Tomcat is configured to have the Java Security Manager turned on. See the sample policy file for more details.

If you want to turn off the Java Security Manager for Tomcat, edit the Tomcat startup script. You might also want to check your /etc/init.d/tomcat file or /etc/default/tomcat5.5. You should see the following code:

# Use the Java security manager? (yes/no)
TOMCAT5_SECURITY=

Set it to no to turn off the Security Manager.

Allowing "/" and "\" in page names

Tomcat completely freaks out when there's a %2F or %5C in URLs and it's not something that can be changed in XWiki. See this note for more information.

You can configure Tomcat to allow "/", by setting the org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH system property to true, as in:

-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

And by setting the org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH system property to true to allow "\", as in:

-Dorg.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH=true

To have both properties permanently enabled on your Tomcat instance, add the lines below to your CATALINA_OPTS environment variable. How to achieve this depends on your operating system, Tomcat distribution and single/multi-instance setup.

-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
-Dorg.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH=true

Apache front-end server

Note that if you're using the Apache web server as a front-end, you also need to configure Apache to allow encoded / and \ (AllowEncodedSlashes NoDecode) and also make sure to use nocanon on the ProxyPass line used.

NotSerializableException

If you get the following:

SEVERE: IOException while loading persisted sessions: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.xwiki.model.internal.reference.LocalStringEntityReferenceSerializer
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.xwiki.model.internal.reference.LocalStringEntityReferenceSerializer
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.defaultReadFields(Unknown Source)

This means that on startup Tomcat tries to load saved Sessions and fails to do so. In this case it fails because some non-serializable object was put in the Servlet Session. To work around the issue you can tell Tomcat to not save sessions.

SEVERE: Error listenerStart

If you get this error in your Tomcat logs then you'll need to enable finer-grained logging configuration to see what's the problem. This involves copying the following content in a WEB-INF/classes/logging.properties file:

org.apache.catalina.core.ContainerBase.[Catalina].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].handlers = java.util.logging.ConsoleHandler

Parameter count exceeded allowed maximum

If you get an error such as the following it means you reached the limit of parameters you can send in a form.

java.lang.IllegalStateException: Parameter count exceeded allowed maximum: 512

You can set the value you want by setting the following in your Tomcat server.xml file:

<Connector port=... maxParameterCount="10000" ></Connector>

ThreadLocal Errors

When you stop XWiki you may see the following type of errors in the Tomcat logs. This is a known limitation of XWiki in cleaning up some ThreadLocal variables. To be safe, we recommend that you stop XWiki by stopping Tomcat (i.e. stopping the Tomcat JVM). This ensures that there won't be any memory leak related to these ThreadLocal variables. If you use the Tomcat Manager to stop the XWiki webapp (by undeploying it), then we recommend to not do that and instead to stop Tomcat and restart it.

SEVERE [Thread-794] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [...] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@1125fc78]) and a value of type [...] (value [...]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

Old Instructions

Note that Tomat 7 is no longer supported.

The Tomcat project has brought a change in the way they handle RequestDispatcher which has caused regressions in XWiki for some versions of Tomcat. Thus you should not use the following Tomcat versions:

  • >= 9.0.0.M5 and < 9.0.0.M10 for the 9.0.x branch (fixed in 9.0.0.M10)
  • >= 8.5.1 and < 8.5.5 for the 8.5.x branch (fixed in 8.5.5)
  • >= 8.0.34 and < 8.0.37 for the 8.0.x branch (fixed in 8.0.37)
  • >= 7.0.70 and < 7.0.71 for the 7.0.x branch (fixed in 7.0.71)

There is an important Classloader related bug in 8.0.32 which makes impossible to use the code macro or write Python scripts so you should avoid this version if possible. See https://bz.apache.org/bugzilla/show_bug.cgi?id=58999.

  • XWiki 12.0+ requires a Tomcat version >= 8 since it requires Servlet 3.1+
  • Older versions of XWiki require a Tomcat version >= 7 since it requires Servlet 3.0+
  • Tomcat 7 is not using URF-8 by default. Edit the conf/server.xml file to set the UTF-8 encoding:
    <Connector port="8080" ... URIEncoding="UTF-8"></Connector>
Tags:
   

Get Connected