The purpose of this two-part series is to show you how to host a Monica CRM server and database on a Kubernetes cluster.

In the previous article, we went over

  • The key Kubernetes components--configMaps, deployments, PVCs, secrets, and services--for our Monica server and MySQL DB
  • How to create the config file for a Kubernetes secret
  • One way to safely store sensitive data, like the config file for a secret, in Git

In Part 2, I'm going to show you how to use an ingress object to

  • Make the Monica server accessible outside of the cluster
  • Enable HTTPS between clients and the cluster

Make Monica Accessible Outside of the Cluster

Pods and services are inherently inaccessible outside of the cluster. This means that we cannot use a browser or curl to make requests to Monica.

The server container lives in a pod in Minikube--a virtual machine acting as a one-node Kubernetes cluster. Curl and the browser run on the computer, but outside of Minikube. Thus, requests from curl or the browser will not reach the Monica server.

To make Monica accessible to requests from outside of Minikube, we need to add a new route to the cluster ingress object.

Add a Route for Monica in the Ingress Config File

In the previous two sets of articles, we used an ingress object to make the Nextcloud and Huginn servers accessible to external requests. Now we're going to update the ingress config file to make Monica accessible as well.

Here is that ingress config file before we add a route for Monica.
cluster-ingress-1-1
And here's what it looks like after we add the code for Monica.
cluster-ingress-1a-1
Requests sent to crm.mysite.test/ will be directed to port 80 on the monica-server service.

Add a New Entry in the "hosts" File

Before we can visit crm.mysite.test/ in the browser, we first need to make sure that that address resolves to the IP of Minikube. Since we are just testing things out locally, we need to add a new entry into the computer's "hosts" file to enable that IP address resolution.

If you are on a Mac or Linux machine, you can edit the "hosts" file using vim:

sudo vim /etc/hosts

Since the IP address of Minikube is 192.168.64.37 on my machine, this is what the new entry looks like:
term-1b
Now we can visit our locally-hosted Monica site.
monica-site-1-2

Upgrade from HTTP to HTTPS between the Browser and the Cluster

In this section, I'm going to show you how to modify the ingress object in order to enable HTTPS between external clients and the cluster.

The first thing that we need to do is add the following tls section to the cluster ingress config file.
cluster-ingress-1b-1
The tls.hosts list contains the domain name for each of the services exposed by this ingress object. The tls.secretName field references the Kubernetes secret which will hold the TLS certificate and key that puts the "S" in HTTPS.

Create the TLS Certificate and Key

If we were deploying to production, we'd need to get a TLS cert and key from a certificate authority like Let's Encrypt. But since we're just testing things out on our local machine, we are going to create a self-signed cert and key using openssl.

openssl genrsa -out tls.key 2048
openssl req -new -x509 -key tls.key -out tls.crt -days 3650 -subj /CN=*.mysite.test

Note that the cert applies to the domain mysite.test and all subdomains, e.g. crm.mysite.test and agents.mysite.test.

Create the TLS-type Kubernetes Secret

Now we need to create a secret named my-tls-secret which stores a copy of the cert and key. The ingress object extracts the cert and key from this secret, and uses it to encrypt HTTP traffic between it and clients external to the cluster. Here's the command to create the secret.

kubectl create secret tls my-tls-secret --cert=tls.crt --key=tls.key

Update the Ingress Object on the Cluster

The ingress object currently running on the cluster is still the old non-HTTPS version. We need to update it to reflect our recent addition of the tls section. So we need to rerun the kubectl apply command.

kubectl apply -f cluster-ingress.yaml

Now let's (re)visit https://crm.mysite.test.
monica-site-1a
The browser gives us a warning (which isn't unexpected). To find out why, click the Advanced button.
monica-site-1b
The browser is warning us that it doesn't trust the organization that issued our cert and key. That's to be expected since we created a self-signed key. It's also why you need to get cert and key from a legitimate certificate authority when deploying to production.

Click the Accept the Risk and Continue button.
monica-site-1c
That's what we call a partial success. Clearly, the CSS is messed up. Let's open up the dev tools and find out why.
monica-site-1d
Here's the key error message:

Blocked loading mixed active content “http://crm.mysite.test/css/app-ltr.css?id=065d5524629b65ed5c99”

Basically, the browser is warning us that the site has requested "app-ltr.css" over HTTP even though the site is delivered via HTTPS. Hence, the "mixed active content" error. This is a Monica server configuration issue.

Reconfigure Monica to Work Over HTTPS

To fix the previous issues, we need to go back to the server configMap, update the APP_ENV from local to production, and add the APP_TRUSTED_PROXIES property.
monica-server-1f
(If you're interested in understanding these Monica environment variables, check out the following documentation: https://github.com/monicahq/monica/blob/master/docs/installation/ssl.md.)

Now we need to update the configMap in the cluster. We'll do so using the kubectl apply command.
term-1c
Notice that the configMap was configured, while the deployment and service were unchanged. This is because we only edited the configMap code.

Make Sure the Server Pod Picks Up the New Env Vars

A container sets its environment variables when it first starts up. Therefore, the current server pod did not pick up the changes in the configMap. The easiest way to fix this problem is to delete the pod and allow the deployment to create a replacement which will have the new environment variables.

So let's list out the pods and copy the name of the Monica server pod.
term-1d
Then let's delete the pod.
term-1e
When we list the pods again, we can clearly see that a new Monica server pod has been created to replace the one that we deleted.
term-1f
We can revisit the site and see that (1) the page is properly styled
and (2) the mixed content error is gone!
monica-site-1e
We have successfully enabled HTTPS using an ingress object!

Summary

We covered a bunch of new things, such as

  • How to create the config file for a Kubernetes secret
  • That you can safely store sensitive data, like the config file for a secret, in Git by using Blackbox
  • How to enable HTTPS between clients and the cluster using an ingress object
  • And how to run Monica in a Kubernetes cluster

I hope you found these articles to be useful. Thanks for checking them out!