What do you think? Discuss, post comments, or ask questions at the end of this article [More about me]

Problem

Confluence uses synchrony for collaborative editing.  By default confluence tries first to access synchrony via the /synchrony context - and if that fails uses confluence's internal proxy.  This usually works fine but is not optimal and is subject to latency and other issues. 

I usually use a reverse-proxy (apache) as described here.  On one of the systems I deployed, we noticed some latency and strange behaviour when editing collaboratively.  The following solutions seems to have solved several issues around using synchrony with a reverse-proxy setup.

Solution

First, you'll need to open port 8091 (the port synchrony uses by default).

An approach outlined in Atlassian when using an Apache reverse proxy is to proxy pass the /synchrony context to port 8091 (default synchrony port).  To do so modify for your confluence virtual host to include the following:

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/synchrony
RewriteRule ^/(.*) http://127.0.0.1:8090/$1 [P]

ProxyPass /synchrony http://127.0.0.1:8091/synchrony
<Location /synchrony>
	Require all granted
	RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
	RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
	RewriteRule .* ws://127.0.0.1:8091%{REQUEST_URI} [P]
</Location>

ProxyPass / http://127.0.0.1:8090/
ProxyPassReverse / http://127.0.0.1:8090/

Note: order is important here in that the synchrony directives should be before the confluence proxy pass arguments.

Note on "ProxyPass !" exceptions

Note that the code above will break any exceptions you might have defined for proxying such as the /robots.txt exception outlined in Global robots.txt on Apache reverse proxy.  This is because the RewriteRule will be rewriting all requests that don't start with "/synchrony".

You'll need to also add other exceptions in new RewriteCond lines.  Note that adding a new line is treated as AND (you'll need to append the [OR] flag for OR logical expressions).

For example, to enable the global robots.txt method outlined here, you would need to add the 3rd line below:

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/synchrony
RewriteCond %{REQUEST_URI} !^/robots.txt$
RewriteRule ^/(.*) http://127.0.0.1:8090/$1 [P]

which basically says:

for all requests NOT starting with /synchonry AND NOT equal to /robots.txt, send to port 8090

Enforcing use of external synchrony connection (i.e. force not to use internal confluence proxy)

I wanted to force (and make sure) that confluence was using websocket connections and not the internal synchrony-proxy.  I wanted to make sure that my reverse-proxy setup was properly resolving the synchrony direct connection.  You may like to do this to force external synchrony connections or just for testing.

To make doubly sure I made changes to two files.  The first change was to /opt/atlassian/confluence/bin/setenv.sh

/opt/atlassian/confluence/bin/setenv.sh
...
# disable synchrony proxy
CATALINA_OPTS="-Dsynchrony.proxy.enabled=false ${CATALINA_OPTS}"

export CATALINA_OPTS

The second change was to /opt/atlassian/confluence/conf/server.xml

/opt/atlassian/confluence/conf/server.xml
...
                <!--
                <Context path="${confluence.context.path}/synchrony-proxy" docBase="../synchrony-proxy" debug="0" reloadable="false" useHttpOnly="true">
                    <Valve className="org.apache.catalina.valves.StuckThreadDetectionValve" threshold="60" />
                </Context>
                -->
...

Note I commented out the above by surrounding the context path argument with "<!–" and "→".

As  long as you've setup your reverse-proxy virtual host correctly, you should still be able to use synchrony features (e.g. collaborative editing).

References

  1. https://confluence.atlassian.com/conf65/administering-collaborative-editing-939701936.html
  2. https://confluence.atlassian.com/conf64/using-apache-with-mod_proxy-936511579.html