This post is far overdue, especially since these products are EoL in 2024. Atlassian never officially supported hosting JIRA or Confluence on FreeBSD, nor did they officially support openJDK. Here's how I got both of them working on the latest FreeBSD 13.2.
- /usr/local/share/confluence/logs/catalina.out
- /usr/local/confluence/confluence-data/logs/atlassian-confluence.log
- /usr/local/share/jira/logs/catalina.out
- /usr/local/jira/log/atlassian-jira.log
Start by obtaining the latest installers from Atlassian. In this guide, I will be using Confluence 8.5.1 and JIRA 9.11.0. I used the tar.gz
files.
curl -OL https://product-downloads.atlassian.com/software/jira/downloads/atlassian-jira-software-9.11.0.tar.gz
curl -OL https://www.atlassian.com/software/confluence/downloads/binary/atlassian-confluence-8.5.1.tar.gz
I chose the following locations for the files:
- Confluence install: /usr/local/share/confluence
- Confluence Home: /usr/local/confluence
- JIRA install: /usr/local/share/jira
- JIRA Home: /usr/local/jira
mkdir /usr/local/share/confluence /usr/local/confluence /usr/local/share/jira /usr/local/jira
Generate service accounts:
pw useradd -n jira -u 71 -c "JIRA Service Account" -s /bin/sh -d /usr/local/jira -w random
pw useradd -n confluence -u 72 -c "Confluence Service Account" -s /bin/sh -d /usr/local/confluence -w random
Extract the tar.gz
files to their respective locations:
tar -xzf atlassian-confluence-8.5.1.tar.gz -C /usr/local/share/confluence
tar -xzf atlassian-jira-software-9.11.0.tar.gz -C /usr/local/share/jira
Change ownership of both installation and home directories:
chown -R confluence /usr/local/share/confluence /usr/local/confluence
chown -R jira /usr/local/share/jira /usr/local/jira
Install the openJDK packages. You'll need version 11 for JIRA and 17 for Confluence:
pkg install openjdk11 openjdk11-jre openjdk17 openjdk17-jre
Neither product comes with the MySQL driver. I'm using MySQL8 so I obtained the files from here: https://dev.mysql.com/downloads/connector/j/8.0.html
You can download either format since you only need to unpack the archive, and move a single file into your JIRA/Confluence install. In this example I'm using the tar.gz file:
cd ~
curl -o mysql_connector.tar.gz -L https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-j-8.1.0.tar.gz
mkdir mysql_connector
tar -xzf mysql_connector.tar.gz -C mysql_connector
cp mysql_connector/mysql-connector-j-<YOUR VERSION HERE>.jar /usr/local/share/confluence/confluence/WEB-INF/lib/
cp mysql_connector/mysql-connector-j-<YOUR VERSION HERE>.jar /usr/local/share/jira/lib/
Create RC scripts for each service. Make sure you update the paths for the <product>_install
and <product_home
variables to match the locations used to install the applications and setup the user's home paths.
vi /usr/local/etc/rc.d/jira
#!/bin/sh
#
# PROVIDE: jira
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subr
load_rc_config jira
JAVA_HOME="/usr/local/openjdk11"
JRE_HOME="/usr/local/openjdk11-jre"
JIRA_INSTALL="/usr/local/share/jira"
JIRA_HOME="/usr/local/jira"
jira_enable=${jira_enable:-"NO"}
jira_user=${jira_user:-"jira"}
name=jira
rcvar=jira_enable
procname="java"
pidfile="/var/run/jira.pid"
start_cmd="jira_start"
stop_cmd="jira_stop"
jira_start()
{
su -l ${jira_user} -c "export JAVA_HOME=${JAVA_HOME};export JRE_HOME=${JRE_HOME};export JIRA_HOME=${JIRA_HOME};${JIRA_INSTALL}/bin/catalina.sh start || err 1 'Error triggering JIRA startup'"
}
jira_stop()
{
su -l ${jira_user} -c "export JAVA_HOME=${JAVA_HOME};export JRE_HOME=${JRE_HOME};export JIRA_HOME=${JIRA_HOME};${JIRA_INSTALL}/bin/catalina.sh stop 10 -force || err 1 'Error triggering JIRA shutdown'"
}
run_rc_command "$1"
vi /usr/local/etc/rc.d/confluence
#!/bin/sh
#
# PROVIDE: confluence
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subr
load_rc_config confluence
JAVA_HOME="/usr/local/openjdk17"
JRE_HOME="/usr/local/openjdk17-jre"
CONFLUENCE_INSTALL="/usr/local/share/confluence"
confluence_enable=${confluence_enable:-"NO"}
confluence_user=${confluence_user:-"confluence"}
name=confluence
rcvar=confluence_enable
procname="java"
pidfile="/var/run/confluence.pid"
start_cmd="confluence_start"
stop_cmd="confluence_stop"
confluence_start()
{
su -l ${confluence_user} -c "export JAVA_HOME=${JAVA_HOME};export JRE_HOME=${JRE_HOME};${CONFLUENCE_INSTALL}/bin/catalina.sh start || err 1 'Error triggering CONFLUENCE startup'"
}
confluence_stop()
{
su -l ${confluence_user} -c "export JAVA_HOME=${JAVA_HOME};export JRE_HOME=${JRE_HOME};${CONFLUENCE_INSTALL}/bin/catalina.sh stop 10 -force || err 1 'Error triggering CONFLUENCE shutdown'"
}
run_rc_command "$1"
Make both RC scripts executable:
chmod +x /usr/local/etc/rc.d/jira /usr/local/etc/rc.d/confluence
For JIRA only, I had to update the bash
path in a few files:
cd /usr/local/share/jira/bin
sed -i '.bak' 's|#!/bin/bash|#!/usr/local/bin/bash|' catalina.sh config.sh start-jira.sh stop-jira.sh
Nginx Reverse Proxy
These next few steps are only required if you place JIRA/Confluence behind a reverse proxy like Nginx.
For Confluence, modify the /usr/local/share/confluence/conf/server.xml
file to be aware of the reverse proxy:
<Server port="8000" shutdown="SHUTDOWN">
<Service name="Tomcat-Standalone">
<Connector port="8090" connectionTimeout="20000" redirectPort="8443"
maxThreads="48" maxPostSize="16777216" minSpareThreads="10"
enableLookups="false" acceptCount="10" URIEncoding="UTF-8"
protocol="org.apache.coyote.http11.Http11NioProtocol"
scheme="https" secure="true" proxyName="<ENTER YOUR DOMAIN HERE.SUBDOMAIN.ROOT>" proxyPort="443"/>
<Engine name="Standalone" defaultHost="localhost">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="false" startStopThreads="4">
<Context path="" docBase="../confluence" reloadable="false" useHttpOnly="true">
<!-- Logging configuration for Confluence is specified in confluence/WEB-INF/classes/log4j.properties -->
<Manager pathname=""/>
<Valve className="org.apache.catalina.valves.StuckThreadDetectionValve" threshold="60"/>
<!-- http://tomcat.apache.org/tomcat-9.0-doc/config/valve.html#Access_Log_Valve -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
maxDays="30"
pattern="%t %{X-AUSERNAME}o %I %h %r %s %Dms %b %{Referer}i %{User-Agent}i"
prefix="conf_access_log"
requestAttributesEnabled="true"
rotatable="true"
suffix=".log"
/>
<!-- http://tomcat.apache.org/tomcat-9.0-doc/config/valve.html#Remote_IP_Valve -->
<Valve className="org.apache.catalina.valves.RemoteIpValve" />
</Context>
<Context path="${confluence.context.path}/synchrony-proxy" docBase="../synchrony-proxy"
reloadable="false" useHttpOnly="true">
<Valve className="org.apache.catalina.valves.StuckThreadDetectionValve" threshold="60"/>
</Context>
</Host>
</Engine>
</Service>
</Server>
You'll want to update the <ENTER YOUR DOMAIN HERE...>
part to match your domain in Nginx. Configuring Nginx is outside the scope of this guide, but Atlassian has detailed information on how to perform that task.
JIRA is a similar edit, but I needed two connectors to enable the application link between the two products:
<?xml version="1.0" encoding="utf-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/>
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
<Service name="Catalina">
<!-- Relaxing chars because of JRASERVER-67974 -->
<Connector port="8080" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`"<>"
maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false"
maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443"
acceptCount="100" disableUploadTimeout="true" bindOnInit="false"/>
<Connector port="8082" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`"<>"
maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false"
maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443"
acceptCount="100" disableUploadTimeout="true" bindOnInit="false" secure="true" scheme="https"
proxyName="<ENTER YOUR DOMAIN HERE.SUBDOMAIN.ROOT>" proxyPort="443"/>
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context path="" docBase="${catalina.home}/atlassian-jira" reloadable="false" useHttpOnly="true">
<Resource name="UserTransaction" auth="Container" type="javax.transaction.UserTransaction"
factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60"/>
<Manager pathname=""/>
<JarScanner scanManifest="false"/>
<Valve className="org.apache.catalina.valves.StuckThreadDetectionValve" threshold="120" />
</Context>
</Host>
<Valve className="org.apache.catalina.valves.AccessLogValve"
pattern="%a %{jira.request.id}r %{jira.request.username}r %t "%m %U%{sanitized.query}r %H" %s %b %D "%{sanitized.referer}r" "%{User-Agent}i" "%{jira.request.assession.id}r""/>
</Engine>
</Service>
</Server>
Again, same as before, update the <ENTER YOUR DOMAIN HERE...>
part to match your Nginx configuration.
At this point, you should be able to start both services with service start jira
and service start confluence
.