๐ Full Guide: Setting Up SSL for Monitoring, Docker, and Kubernetes (MicroK8s)


๐ Introduction
Securing your services with SSL is crucial for any production environment. In this blog, Iโll share how I configured SSL certificates (Let's Encrypt) across three major environments:
Monitoring stack (Grafana, Prometheus, cAdvisor)
Docker-based WordPress deployment
Kubernetes MicroK8s deployments using Ingress
โ Step 1: SSL for Monitoring Stack (Grafana, Prometheus, cAdvisor)
๐ง Nginx Reverse Proxy Configuration
# Redirect all HTTP traffic to HTTPS
server {
listen 80;
server_name grafana.hassandevops.site prometheus.hassandevops.site cadvisor.hassandevops.site;
return 301 https://$host$request_uri;
}
# Grafana HTTPS
server {
listen 443 ssl;
server_name grafana.hassandevops.site;
ssl_certificate /etc/letsencrypt/live/hassandevops.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hassandevops.site/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# Prometheus HTTPS
server {
listen 443 ssl;
server_name prometheus.hassandevops.site;
ssl_certificate /etc/letsencrypt/live/hassandevops.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hassandevops.site/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:9090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# cAdvisor HTTPS
server {
listen 443 ssl;
server_name cadvisor.hassandevops.site;
ssl_certificate /etc/letsencrypt/live/hassandevops.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hassandevops.site/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
๐ SSL Certificate Placement:
/etc/ssl/hassandevops.site/fullchain.pem
/etc/ssl/hassandevops.site/privkey.pem
โ Step 2: Docker WordPress SSL Setup (docker.hassandevops.site)
๐ Docker Compose:
version: '3.8'
services:
wordpress:
image: wordpress
restart: always
ports:
- 127.0.0.1:8081:80 # Only accessible from localhost
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html
db:
image: mysql:8.0
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql
volumes:
wordpress:
db:
๐ง Docker Nginx Reverse Proxy:
server {
listen 80;
server_name docker.hassandevops.site;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name docker.hassandevops.site;
ssl_certificate /etc/ssl/hassandevops.site/fullchain.pem;
ssl_certificate_key /etc/ssl/hassandevops.site/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
๐ Certificate copied via SCP:
scp -r /etc/ssl/hassandevops.site root@Docker-Server:/etc/ssl/hassandevops.site
โ Step 3: Kubernetes (MicroK8s) SSL via Ingress - WordPress & NGINX Apps
๐ SSL Certificate copied to K8s Server:
scp -r /etc/ssl/hassandevops.site root@K8s-Server:/etc/ssl/hassandevops.site
๐ Kubernetes Ingress with Custom TLS:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 1
selector:
matchLabels:
app: nginx-app
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: nginx-app
image: nginx:1.14.2
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx-app
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- nginx.hassandevops.site
secretName: hassandevops-tls
rules:
- host: nginx.hassandevops.site
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_DATABASE
value: exampledb
- name: MYSQL_USER
value: exampleuser
- name: MYSQL_PASSWORD
value: examplepass
- name: MYSQL_RANDOM_ROOT_PASSWORD
value: "1"
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
---
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
selector:
app: mysql
ports:
- protocol: TCP
port: 3306
targetPort: 3306
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
replicas: 1
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
- name: wordpress
image: wordpress
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: mysql
- name: WORDPRESS_DB_USER
value: exampleuser
- name: WORDPRESS_DB_PASSWORD
value: examplepass
- name: WORDPRESS_DB_NAME
value: exampledb
volumeMounts:
- name: wordpress-storage
mountPath: /var/www/html
volumes:
- name: wordpress-storage
persistentVolumeClaim:
claimName: wordpress-pvc
---
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
selector:
app: wordpress
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wordpress-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- wordpress.hassandevops.site
secretName: hassandevops-tls
rules:
- host: wordpress.hassandevops.site
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wordpress
port:
number: 80
๐ TLS Secret Creation:
kubectl create secret tls nginx-tls --cert=/etc/ssl/hassandevops.site/fullchain.pem --key=/etc/ssl/hassandevops.site/privkey.pem
kubectl create secret tls wordpress-tls --cert=/etc/ssl/hassandevops.site/fullchain.pem --key=/etc/ssl/hassandevops.site/privkey.pem
๐ Final Outcome:
โ
https://grafana.hassandevops.site - Secured
โ
https://cadvisor.hassandevops.site - Secured
โ
https://docker.hassandevops.site - WordPress on Docker Secured
โ
https://nginx.hassandevops.site - NGINX App on K8s Secured
โ
https://wordpress.hassandevops.site - WordPress on K8s Secured
๐ฏ Conclusion:
This setup ensures your entire monitoring stack, Docker deployments, and Kubernetes services are secured with valid SSL certificates.
Proper reverse proxy configuration, TLS secret handling, and using Let's Encrypt certificates bring production-level security to your projects.
Subscribe to my newsletter
Read articles from Muhammad Hassan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Muhammad Hassan
Muhammad Hassan
Hey there! I'm currently working as an Associate DevOps Engineer, and I'm diving into popular DevOps tools like Azure Devops,Linux, Docker, Kubernetes,Terraform and Ansible. I'm also on the learning track with AWS certifications to amp up my cloud game. If you're into tech collaborations and exploring new horizons, let's connect!