Jira Selfhosted w/ SSL
This is a guide on how to install JIRA on your own VPS, including a SSL Certificate from Letsencrypt without the Tomcat SSL Keyfile stuff (and also without apache or nginx as a proxy).
Requirements
- Fully licensed JIRA (10$ for a lifetime license with 10 seats)
- Public Domain
- Virtual Private Server / Dedicated Server with a public IP
- A Linux derivative OS (Debian/Ubuntu/CentOS/etc.)
Setup
→ Install JIRA based on the atlassian documentation
su root
wget https://product-downloads.atlassian.com/software/jira/downloads/atlassian-jira-software-7.12.1-x64.bin
chmod +x atlassian-jira-*
./atlassian-jira-*
# Follow the installation guide
Installation Directory: /opt/atlassian/jira
Home Directory: /var/atlassian/application-data/jira
HTTP Port: 8443
RMI Port: 8005
Install as service: Yes
ufw allow 8443/tcp
# postgresql
apt-get install -y postgresql
su postgres
psql
/* jira database */
CREATE USER jira_admin;
CREATE DATABASE jira;
ALTER USER jira_admin with encrypted password '<passwd>';
GRANT ALL PRIVILEGES ON DATABASE jira TO jira_admin;
create /etc/systemd/system/jira.service
# /etc/systemd/system/jira.service
[Unit]
Description=Jira Issue & Project Tracking Software
After=network.target
[Service]
Type=forking
User=jira
PIDFile=/opt/atlassian/jira/work/catalina.pid
ExecStart=/opt/atlassian/jira/bin/start-jira.sh
ExecStop=/opt/atlassian/jira/bin/stop-jira.sh
[Install]
WantedBy=multi-user.target
→ SSH into your server
# on your client pc:
ssh remote -L 8443:localhost:8443
→ [optional] setup a screen or tmux session for installation safety
→ Begin the SSL Hacking:
# FIRST: STOP JIRA
systemctl stop jira
# Update Package Lists
apt-get update
# open Port 22 (SSH) and enable the firewall
# Might be different when using CentOS/Fedora/etc.
ufw allow 22/tcp
ufw enable
# Set the following environment variables for a quicker setup
# The Path you specified for your jira installation
export JIRA_INSTALL="/opt/atlassian/jira"
# Your domain that either has a certifcate or needs one via Letsencrypt
export DOMAIN="jira.yourdomain.com"
# Your Email that you want to link to your Letsencrypt certificate
export EMAIL="foo@bar.com"
# Locale Language for the installation (optional, but nice to have)
export LC_ALL="en_US.utf8"
Tomcat APR
→ To use SSL Certificates without the tomcat keystore crap, we need the apache portable runtime.
Unfortunately, this is only available when building on our own. I see no problem in that.
# INSTALL APACHE PORTABLE RUNTIME FOR JIRA
# TOMCAT: 8.x
# JIRA: 7.12.1
# ----------------------------------------
# run as root: sudo su || su root
# GNU development environment (gcc, make)
apt-get install -y build-essential
# APR 1.2+ development headers (libapr1-dev package)
apt-get install -y libapr1-dev
# OpenSSL 0.9.7+ development headers (libssl-dev package)
apt-get install -y libssl-dev
# JNI headers from Java compatible JDK 1.4+
apt-get install -y openjdk-8-jdk-headless
# Extract jiras tomcat-native
tar -xzvf ${JIRA_INSTALL}/bin/tomcat-native.tar.gz -C /tmp
# Configure Tomcat
cd /tmp/tomcat-native-*/native && \
./configure --with-apr=/usr/bin/apr-1-config --with-java-home=/usr/lib/jvm/java-8-openjdk-amd64 --with-ssl=yes \
&& make && make install
# Libraries will be installed in /usr/local/apr/lib
# Defaults: /lib:/lib64:/usr/lib:/usr/lib64:/usr/java/packages/lib/amd64
# Append additional Java options to the startup script.
tee -a ${JIRA_INSTALL}/bin/setenv.sh > /dev/null << END
#-----------------------------------------------------------------------------------
# Include PATH for Tomcat <--> Apache Portable Runtime Library
#-----------------------------------------------------------------------------------
export JAVA_OPTS="\${JAVA_OPTS} -Djava.library.path=/lib:/lib64:/usr/lib:/usr/lib64:/usr/java/packages/lib/amd64:/usr/local/apr/lib"
END
Lets Encrypt
# Install Letsencrypt Certbot
apt-get install -y certbot
# Allow Port 80 for
ufw allow 80/tcp
# Create a Certificate
certbot certonly --non-interactive --standalone -d ${DOMAIN} --agree-tos -m ${EMAIL}
# Since JIRA does not like symlinks, we have to copy them elsewhere:
# create custom directory for our SSL certs
mkdir -p /opt/atlassian/ssl
# Copy certificates, while dereferencing the symlink:
cp --dereference \
/etc/letsencrypt/live/${DOMAIN}/cert.pem \
/opt/atlassian/ssl/${DOMAIN}-cert.pem
cp --dereference \
/etc/letsencrypt/live/${DOMAIN}/privkey.pem \
/opt/atlassian/ssl/${DOMAIN}-key.pem
# Add the Letsencrypt chain to jiras keystore
# The password actually *is* "changeit"
/opt/atlassian/jira/jre/bin/keytool -trustcacerts \
-keystore ${JIRA_INSTALL}/jre/lib/security/cacerts -storepass changeit \
-noprompt -importcert -file /etc/letsencrypt/live/${DOMAIN}/chain.pem
# (Optional) manually verify:
# ls -l /opt/atlassian/ssl
# Move the server.xml:
mv ${JIRA_INSTALL}/conf/server.xml ${JIRA_INSTALL}/conf/server.xml.orig
# Create a new server.xml
# BEWARE:
# The Variables have to be resolved in this file,
# so copy it "as is" or resolve them manually.
# NOTE:
# If you want a specific SSL port,
# do this here in the <Connector port=SSLPORT> property
cat > /opt/atlassian/jira/conf/server.xml << EOF
<?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">
<!-- Custom Jira SSL Connector with APR -->
<Connector
protocol="org.apache.coyote.http11.Http11AprProtocol"
port="443"
scheme="https"
secure="true"
SSLEnabled="true"
SSLProtocol="TLSv1.2+TLSv1.3"
maxThreads="200"
minSpareThreads="25"
useBodyEncodingForURI="true"
maxHttpHeaderSize="8192"
connectionTimeout="20000"
enableLookups="false"
disableUploadTimeout="true"
acceptCount="100"
clientAuth="false"
SSLCertificateFile="/opt/atlassian/ssl/${DOMAIN}-cert.pem"
SSLCertificateKeyFile="/opt/atlassian/ssl/${DOMAIN}-key.pem"
SSLVerifyClient="optional">
</Connector>
<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"/>
</Context>
</Host>
<Valve className="org.apache.catalina.valves.AccessLogValve"
pattern="%a %{jira.request.id}r %{jira.request.username}r %t "%m %U%q %H" %s %b %D "%{Referer}i" "%{User-Agent}i" "%{jira.request.assession.id}r""/>
</Engine>
</Service>
</Server>
EOF
# empty the tomcat logs
truncate -s 0 /opt/atlassian/jira/logs/catalina.out
# FINALLY JIRA
systemctl start jira
# Observe the Tomcat output and check for errors:
tail -f /opt/atlassian/jira/logs/catalina.out