Apache virtual hosts, HTTPS, and JIRA Docker Containers

September 8th, 2017

tl;dr

The goal was to easily create and recreate docker instances protected via SSL and accessed by simple URL. Below I explain how to map https://jira.example.com/ and https://git.example.com/ in apache (used as firewall, reverse proxy, content server) to a specified IP:port of Jira and Bitbucket (git) docker container.

Overview

Docker is awesome, can easily create a new web service in minimal time.  However, in my case, I want everything to be routed through one machine’s https (port 443).  Additionally I wanted to setup Jira and Bitbucket (and possibly more). Previously I had to use github.com to view my private repositories from a web browser.  I show how to do this with apache 2.4 and docker on a single Ubuntu Linux machine.

  • Security – single apache instance serves as reverse proxy and can force all HTTP requests to use HTTPS.
  • HTTPS certificates – use certbot by Let’s Encrypt to easily install certificates for HTTPS to work for free.
  • DNS and Virtual hosts – Assuming multiple domains or subdomains all get routed to same apache instance.  Will configure apache conf files to map these requests to correct port and path on docker container.
  • Creating / Starting JIRA and Bitbucket (git) docker containers to listen on a specific port

Note that you should replace example.com everywhere used in this doc with your domain name.

atlassian-docker-apache

longlonglonglong

DNS

Goal is for several domains, example.com, jira.example.com, test-jira.example.com, git.example.comtest-git.example.com, and bitbucket.example.com, to resolve to the machine where apache will run.  There are many ways to do this, I have one A record mapping example.com to an IP, and  CNAME records mapping the subdomains to example.com.

Apache Setup

I use Apache as the reverse proxy because of its popularity and my experience with it.  If performance is an issue, nginx is probably better.  Below you’ll find the important bits from these apache conf files:

  • apache2.conf
  • sites-enabled/example.com.conf
  • sites-enabled/jira.example.com.conf
  • sites-enabled/git.example.com.conf
  • sites-enabled/000-default.conf
  • conf-available/certbot.example.com.conf
  • conf-available/vhost.logging.conf
> grep sites-enabled apache2.conf
IncludeOptional sites-enabled/*.conf
> cat /etc/apache2/sites-enabled/example.com.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>

 ServerName example.com

 DocumentRoot /var/www/example.com

 Include conf-available/vhost.logging.conf
 Include conf-available/certbot.example.com.conf 
</VirtualHost> 
</IfModule>
> cat /etc/apache2/sites-enabled/jira.example.com.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>

 ServerName jira.example.com

 <Proxy *>
   Order allow,deny
   Allow from all
 </Proxy>
 ProxyRequests Off
 ProxyPreserveHost On
 # below must map to docker ip:port setup
 ProxyPass / http://127.0.0.1:8080/
 ProxyPassReverse / http://127.0.0.1:8080/

 Include conf-available/vhost.logging.conf
 Include conf-available/certbot.example.com.conf
</VirtualHost>
</IfModule>
> cat /etc/apache2/sites-enabled/git.example.com.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>

 ServerName git.example.com
 ServerAlias bitbucket.example.com

 <Proxy *>
   Order allow,deny
   Allow from all
 </Proxy>
 ProxyRequests Off
 ProxyPreserveHost On
 # below must map to docker ip:port setup
 ProxyPass / http://127.0.0.1:7990/
 ProxyPassReverse / http://127.0.0.1:7990/

 Include conf-available/vhost.logging.conf
 Include conf-available/certbot.example.com.conf 
</VirtualHost> 
</IfModule>
> cat /etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:80>

 DocumentRoot /var/www/html
 Include conf-available/vhost.logging.conf

 # Redirect http (port 80) to https (port 443)
 RewriteEngine on
 RewriteCond "%{SERVER_NAME}" ".*\.example.com$" [OR]
 RewriteCond %{SERVER_NAME} =example.com
 RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]

</VirtualHost> 
> cat /etc/apache2/conf-available/certbot.example.com.conf
# added by certbot-auto
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
> cat /etc/apache2/conf-available/vhost.logging.conf
LogFormat "%{Host}i:%p %h %l %u [%{%d/%b/%Y %T}t.%{msec_frac}t %{%z}t] %{us}T \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined2
CustomLog ${APACHE_LOG_DIR}/access.vhosts.log vhost_combined2
ErrorLog ${APACHE_LOG_DIR}/error.log

 

HTTPS Certificates

With letsencrypt.org, you can get free certificates from a Certificate Authority (CA). I used the cmd-line certbot to install them and update them. Initial setup can take up to 30 minutes, but every 3 months when you renew it should only take a few minutes. I do this on Ubuntu linux, but they have instructions for all the popular flavors of linux.  When done, you can verify your installed certificate using https://www.ssllabs.com/ssltest/analyze.html?d=example.com

One thing to note here is that its easiest to have a single certificate to cover domain and subdomains. In January 2018 wildcard certs will be supported, but till then you’ll need to start with something like this:

cd ssl-certs && ./certbot-auto --apache \
-d example.com \
-d jira.example.com 
-d git.example.com -d bitbucket.example.com 

Docker Setup

Docker is the new cool kid on the block, and as such, it is constantly improving.  So what I write here may not be exactly what you need to do.  In any case, what I did is setup 3 docker containers – one for Jira, one for Bitbucket, and one for Postgres database.  If you don’t have experience setting up Jira or Bitbucket, it can be tricky, but Atlassian has pretty good documentation.

I have created a sample docker-compose.yml that covers whats needed on the docker side.  As previously mentioned, you will need to replace example.com with your domain name.