teamatldocker / confluence

Dockerized Atlassian Confluence
https://hub.docker.com/r/teamatldocker/confluence/
MIT License
301 stars 147 forks source link

Allow Synchrony usage behind HTTPS-Proxy #2

Closed kiview closed 7 years ago

kiview commented 7 years ago

There is some buggy behavior in Confluence regarding Synchrony if run behind an HTTPS-Rerverse-Proxy: https://jira.atlassian.com/browse/CONF-45264

If configuring the image with environment variable CONFLUENCE_PROXY_SCHEME as https, Confluence will deactivate the internal synchrony proxy (I'm not sure if this is a bug or by design?). This makes using the image behind a Traefik proxy impossible, if you want to use the collaborative editing feature.

So I'm not entirely sure if this is a problem of the image or a bug in Confluence, but I thought it useful to document this problem here.

blacklabelops commented 7 years ago

It's a Confluence issue. My environment variable just sets some config parameters inside Confluence's server.xml. The behavior is then triggered by Confluence itself.

Please take a look at my nginx configuration, it should help you with an alternative Traefik setup:

location /synchrony {
          set $backend "http://confluence:8091";
          proxy_pass $backend;
          proxy_redirect http://confluence:8091 $scheme://$host/;
          proxy_set_header X-Forwarded-Host $host;
          proxy_set_header X-Forwarded-Server $host;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
        }

location / {
          set $backend "http://confluence:8090";
          proxy_pass $backend;
          proxy_redirect http://confluence:8090 $scheme://$host/;
          proxy_set_header X-Forwarded-Host $host;
          proxy_set_header X-Forwarded-Server $host;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

You can setup two reverse proxies! One for confluence and one for synchrony. The synchrony reverse proxy will be forwarded to the synchrony port and is therefore not dependent on the internal Confluence proxy.

In my example the /synchrony reverse proxy must be defined before the root path /. Otherwise all would be matched against / and routed to 8090.

Hope this helps.

kiview commented 7 years ago

I'm not entirely sure if this would work with Traefik, since Traefik simply autodiscovers the running docker containers and makes them accessible via subdomains. I'm not sure if Traefik supports mixing of backends (this would be a docker backend and a manual, rule based backend in this case).

Maybe it would work if I setup an additional nginx proxy between Traefik and Confluence, which would be configured like you suggested.

I hope Atlassian will make the deactivation of the internal proxy configurable, this would eliminate this problem as well.

blacklabelops commented 7 years ago

This is already possible. You can edit the confluence.cfg.xml inside the confluence home directory.

You can edit the xml like this:

$ docker exec -it confluence bash
$ vi confluence.cfg.xml

You have to consult the Atlassian documentation on which properties symphony uses! I have seen it somewhere. You can enable the proxy and change symphony server ports.

kiview commented 7 years ago

Thx, I did not knew about this. I will look into this tomorrow and if I find a working solution, we might be able to make this configurable via environment variables?

blacklabelops commented 7 years ago

Please test if the setting will solve your problem, afterwards I can provide an image where you can set those setting through environment variables.

Link: https://confluence.atlassian.com/doc/configuring-system-properties-168002854.html

Property: synchrony.proxy.enabled

kiview commented 7 years ago

Sadly this does not work. I've already had this property set to true. Confluence will always try access synchrony via /synchrony instead of /synchrony-proxy once it detects a proxy configuration inside the server.xml.

So I'd say this is an Confluence upstream bug. I'm still communicating with Atlassian about this problem inside a support ticket, maybe I'll get further insights soon.

kiview commented 7 years ago

This was the bug ticket that was created after filing this bug at Atlassian: https://jira.atlassian.com/browse/CONF-45264

It has been closed in release 6.0.2, as well as some other synchrony related stuff. This might be worth a try.

ddean4040 commented 7 years ago

Worked through this and wanted to share that the proxy does need to be enabled as a system property in setenv.sh.

An image that would let us set properties through env vars would be amazing. Right now I'm mounting a volume to <confluence install>/bin to persist the change. That's enough to enable collaborative editing behind Traefik and no intermediate nginx proxy is needed.

This ticket has the string for enabling the proxy under "Workaround": https://jira.atlassian.com/browse/CONF-45728

kiview commented 7 years ago

Great that you've found a workaround, we still aren't using synchrony because of this problem. I'm no entirely sure, but wouldn't it be enough to set the CATALINA_OPTS value as a real environment variable, since Tomcat injects this system environment variable into its context?

blacklabelops commented 7 years ago

Okay, envs for setting properties inside confluence.cfg.xml. Im right on it!

blacklabelops commented 7 years ago

Workaround:

$ docker run -d -p 80:8090 -p 8091:8091 \
    --name confluence \
    -e "CATALINA_OPTS=-Dsynchrony.proxy.enabled=true -Xms1g -Xmx2g" \
    blacklabelops/confluence
blacklabelops commented 7 years ago

Can please someone check the feature?

Feature available in new development image: blacklabelops/confluence:development.

Readme

Example:

$ docker run -d -p 80:8090 -p 8091:8091 \
    --name confluence \
    -e "CONFLUENCE_CONFIG_PROPERTY1=synchrony.proxy.enabled" \
    -e "CONFLUENCE_CONFIG_VALUE1=true" \
    blacklabelops/confluence:development
kiview commented 7 years ago

I'll try it monday at work ASAP.

blacklabelops commented 7 years ago

Thanks, that's awesome!

kiview commented 7 years ago

Did not work for me, Confluence still trying to access synchrony/resources/js/vendor/sockjs.min.js instead of using synchrony-proxy/resources/js/vendor/sockjs.min.js.

This is my environment config:

services:
  confluence:
    image: blacklabelops/confluence:development
    container_name: confluence
    restart: always
    ports:
      - "8091:8091"
    labels:
      - "traefik.docker.network=traefik_default"
      - "traefik.port=8090"
    networks:
      - default
      - traefik_default
    volumes:
      - confluencedata:/var/atlassian/confluence
      - /opt/keystore/cacerts:/opt/java/jre1.8.0_92/lib/security/cacerts
    environment:
      - 'CATALINA_OPTS= -Xms256m -Xmx2g'
      - 'CONFLUENCE_DELAYED_START='
      - "CONFLUENCE_PROXY_NAME=confluence.${DOMAIN_NAME}" 
      - "CONFLUENCE_PROXY_PORT=443" 
      - "CONFLUENCE_PROXY_SCHEME=https" 
      - "CONFLUENCE_CONFIG_PROPERTY1=synchrony.proxy.enabled"
      - "CONFLUENCE_CONFIG_VALUE1=true"
blacklabelops commented 7 years ago

I have just installed a new Confluence 6.0.4 instance. synchrony.proxy.enabled= true by default and collaborative editing calls for example:

ws://localhost/synchrony-proxy/sockjs/v1/380/n1trnnrl/websocket

All in all the synchrony behavior seems to have changed drastically from Confluence 6.0.0 to 6.0.4.

blacklabelops commented 7 years ago

In your example you map the synchrony port on the host machine and use traefik as a load balander/proxy on port 8090, right?

I assume you configured everything correctly and in my opinion it should work but let me just clearify the following:

Your proxy runs under confluence.${DOMAIN_NAME}. So the domain name is specified a an env on your docker cli. Have you checked that ${DOMAIN_NAME} is correctly changed during container startup?

Also in order this works your host have to be also available under confluence.${DOMAIN_NAME}, right?

kiview commented 7 years ago

The mapping of the synchrony doesn't do anything useful, that's just something left over from trying out the workarounds.

I use traefik on a proxy on port 8090, that's correct. The $DOMAIN_NAME is specified when deploying the service via Ansible, the host is running under confluence.$DOMAIN_NAME, that's correct.

blacklabelops commented 7 years ago

Perhaps the problem is that 8090 is encrypted https and 8091 over host is not? <- My misunderstanding. We do not need the additional port when synchrony communicates over the context.

ddean4040 commented 7 years ago

Looks like the properties are being written to the confluence.cfg.xml config, but they need to be in setenv.sh or as ENV variables to work. I agree that this seems to be totally different from how the settings worked when 6.0 was first released.

I'm including a simple working service config below. Replacing the CATALINA_OPTS line with CATALINA_CONFIG_PROPERTY / VALUE lines breaks collaborative editing.

docker service create \
  --name confluence \
  --network dmz \
  --replicas 1 \
  --mount type=volume,source=persistent_confluence-var,destination=/var/atlassian/confluence \
  --env "CONFLUENCE_PROXY_NAME=docs.example.com" \
  --env "CONFLUENCE_PROXY_PORT=443" \
  --env "CONFLUENCE_PROXY_SCHEME=https" \
  --env "CATALINA_OPTS=-Dsynchrony.proxy.enabled=true " \
  --label traefik.docker.network=dmz \
  --label traefik.backend=confluence \
  --label traefik.frontend.entryPoints=http,https,ws,wss \
  --label traefik.frontend.rule=Host:docs.example.com \
  --label traefik.port=8090 \
 blacklabelops/confluence
blacklabelops commented 7 years ago

Let me summarize:

blacklabelops/confluence does not accept synchrony.proxy.enabled=true and does not start the proxy under /synchrony-proxy. It needs the env variable CATALINA_OPTS or value in setenv.sh -> blacklabelops/confluence is Confluence 6.0.4

I have tried blacklabelops/confluence:development which is Confluence 6.0.6. Confluence 6.0.6 has the synchrony.proxy.enabled=true by default installation inside confluence.cfg.xml. And it starts the context /synchrony-proxy and calls it.

@ddean4040 Can you please try blacklabelops/confluence:development without CATALINA_OPTS=-Dsynchrony.proxy.enabled=true just to clarify things? Your help is much appreciated!

kiview commented 7 years ago

The solution from @ddean4040 using CATALINA_OPTS works for us as well :)

You don't need an exposed synchrony port. All communication will happen using the Confluence port and the internal proxy, which is redirected by Confluence itself, using the synchrony-proxy/ address (that's at least my understand).

blacklabelops commented 7 years ago

Okay I will see into a solution to add parameters inside setenv.sh.

ddean4040 commented 7 years ago

@blacklabelops Just wanted to follow up that I tried the same config without CATALINA_OPTS and editing did not work. Confluence is trying the /synchrony address.

@kiview That is my understanding as well. We're trying to use the "Reverse proxy with internal Synchrony proxy" setup as described here: https://confluence.atlassian.com/doc/administering-collaborative-editing-858772086.html#AdministeringCollaborativeEditing-ReverseproxywithinternalSynchronyproxy

blacklabelops commented 7 years ago

blacklabelops/confluence:development with new prototype feature. Setting catalina properties with envs:

$ docker run -d -p 80:8090 \
    --name confluence \
    -v confluencedata:/var/atlassian/confluence \
    -e "CATALINA_CONFIG_PROPERTY1=synchrony.proxy.enabled" \
    -e "CATALINA_CONFIG_VALUE1=true" \
    blacklabelops/confluence:development

Will only work with property=value like parameters. The problem is the atlassian default setenv.sh:

Won't work or even corrupt every line with multiple parameters in one line. Example:

CATALINA_OPTS="-Xms1024m -Xmx1024m -XX:+UseG1GC ${CATALINA_OPTS}"

Won't work with parameters without an =, e.g. Xms1024m.

blacklabelops commented 7 years ago

Okay the catalina opts feature has now matured and changed. Now works with any kind of key-value-pair for catalina opts: vm-parameters, properties etc.

New Example:

docker run -d -p 80:8090 \
    -p 8091:8091 --name confluence \
    -v confluencedata:/var/atlassian/confluence \
    -e "CATALINA_PARAMETER1=-Dsynchrony.proxy.enabled=" \
    -e "CATALINA_PARAMETER_VALUE1=true" \
        -e "CATALINA_PARAMETER2=-Xms" \
    -e "CATALINA_PARAMETER_VALUE2=1024m" \
        -e "CATALINA_PARAMETER3=-Xmx" \
    -e "CATALINA_PARAMETER_VALUE3=1024m" \
    blacklabelops/confluence:development
sgohl commented 6 years ago

just as a note for someone who finds this issue but is using the official confluence image with Traefik:

  -e "JVM_SUPPORT_RECOMMENDED_ARGS=-Dsynchrony.port=8092" \
  --label "traefik.enable=true" \
  --label "traefik.confluence.port=8090" \
  --label "traefik.synchrony.port=8092" \
  --label "traefik.confluence.frontend.rule=Host:wiki.example.com" \
  --label "traefik.synchrony.frontend.rule=Host:wiki.example.com;PathPrefix:/synchrony;" 

I changed the synchrony.port because 8091 is already used as a connector for interconnecting with other atlassian apps.

kurtuluso commented 4 years ago

Check First: https://<your confluence address>/synchrony-proxy/resources/js/synchrony.min.js should work

In my case, in Edit Page screen tries to reach synchrony with https://mydomain.com/synchrony/resources/js/synchrony.min.jswhich is invalid (the valid one is above)

I was using proxy as /cf => http://hostname:8090/cf

Then I've added another proxy to my apache/ web server /synchrony => http://hostname:8090/cf/synchrony-proxy

Then now https://mydomain.com/synchrony/resources/js/synchrony.min.js goes to http://hostname:8090/synchrony-proxy/resources/js/synchrony.min.js which is a valid URL