Apereo CAS - Dockerized Deployment via NGINX

Posted by Misagh Moayyed on May 26, 2020 · 5 mins read
This post is largely inspired by this guide.

A dockerized CAS deployment allows one to run multiple CAS servers on a single VM, where each server might be configured differently to address different needs for authentication policy, attribute release, etc. To avoid conflicts and achieve better separation of concerns, we can use Docker and NGINX to host multiple CAS containers behind a proxy, in their isolated network and let the proxy offload the SSL context onto the Docker container running CAS and correctly route traffic.

As is pointed out by the referenced guide,

That’s exactly what nginx-proxy does: it listens to port 80 (the standard HTTP port) and forwards incoming requests to the appropriate container. This is often known as a reverse proxy, and takes advantage of Docker’s VIRTUAL_HOST variable.

Our starting position is as follows:

NGINX Configuration

First, we need to create a Docker network that we will use to bridge all of these containers together.

docker network create nginx-proxy

Then, let’s run the proxy on port 80:

# Run proxy on port 80
docker run -d -p80:80 --name nginx-proxy --net nginx-proxy -v \
    /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

The bit about /var/run/docker.sock:/tmp/docker.sock is important. It gives the container access to the host’s Docker socket, which contains information about a variety of Docker events, such as creating a new container or shutting one down.

As is pointed out by the referenced guide,

This means that every time you add a container, nginx-proxy sees the event through the socket, automatically creates the configuration file needed to route traffic, and restarts nginx to make the changes available immediately by looking for containers with the VIRTUAL_HOST variable enabled.

CAS Configuration

Let’s assume that our CAS container is going to be available via DNS at foo.bar.com. The easiest way, for now, would be to simply map this host to 127.0.0.1 in your operating system’s host file.

Then, in CAS overlay’s etc/cas/config/cas.properties add the following lines:

# Allow X-Forward-Proto Header to handle port 80 and http
server.tomcat.protocol-header-https-value=http

# Run on port 80; disable SSL for now
server.port=80
server.ssl.enabled=false

When you are done, save the file and build the CAS docker image:

./docker-build.sh

Once the image is built, run the container:

docker run -d --expose 80 --net nginx-proxy \
    -e VIRTUAL_HOST=foo.bar.com --name="cas" \
    org.apereo.cas/cas:v6.2.0-SNAPSHOT \

The proxy listens and adds an entry for the virtual host automatically to the NGINX config file, and restarts it for full effect. Also, note how the container is running in its isolated network via --net nginx-proxy sharing it with the NGINX proxy itself.

Watch the CAS logs to make sure the server is ready:

docker logs -f cas

…and then finally, test the configuration to validate how NGINX is proxying traffic onto the appropriate CAS container:

curl -k -v -I http://foo.bar.com/cas/login

SSL Configuration

Once you have configured NGINX and the proxy to handle SSL and certificates, you also need to make sure this property accounts for those changes in CAS:

server.tomcat.protocol-header-https-value=https

So…

I hope this review was of some help to you and I am sure that both this post as well as the functionality it attempts to explain can be improved in any number of ways. Please know that all other use cases, scenarios, features, and theories certainly are possible as well. Feel free to engage and contribute as best as you can.

Happy Coding,

Misagh Moayyed