Minikube’s default HTTP setup is fine for local development, but eventually you’ll want to test your application’s HTTPS behavior. This usually means serving your app over TLS, which for local development means dealing with self-signed certificates.
Here’s how to get Minikube to serve your local services over HTTPS using self-signed certificates.
First, let’s get a basic service running in Minikube that we’ll later expose over HTTPS. We’ll use a simple Nginx deployment.
kubectl create deployment nginx-test --image=nginx
kubectl expose deployment nginx-test --port=80 --type=NodePort
Now, let’s find the NodePort assigned to our Nginx service.
kubectl get service nginx-test
You’ll see output like this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-test NodePort 10.101.11.222 <none> 80:31234/TCP 1m
The important part is 80:31234/TCP. The 31234 is the NodePort. Minikube’s IP address can be found with minikube ip. Let’s assume it’s 192.168.49.2. So, you can access your Nginx deployment at http://192.168.49.2:31234.
Now, let’s tackle the HTTPS part. We need a certificate and a private key for our local domain. Since we’re using Minikube, we’ll typically be accessing services via the Minikube IP and a NodePort, or by using minikube tunnel and an Ingress. For simplicity, let’s focus on direct NodePort access first, which means we need a certificate that covers the Minikube IP and potentially a hostname.
We can generate a self-signed certificate using openssl.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key \
-out tls.crt \
-subj "/CN=minikube-local.com/O=minikube-local"
This creates tls.key (your private key) and tls.crt (your certificate). The /CN (Common Name) is crucial. While technically minikube-local.com isn’t a real domain you’re browsing to, it’s what the browser will check against the certificate. You could also use your Minikube IP here, but a hostname is generally better practice.
Next, we need to store these as a Kubernetes Secret. Secrets are the standard way to store sensitive information like TLS certificates.
kubectl create secret tls my-tls-secret --key tls.key --cert tls.crt
Now, we need to tell our Nginx deployment to use these TLS credentials. We can do this by mounting the secret as a volume into the Nginx pod and then configuring Nginx to use those files. We’ll need to edit our deployment.
First, let’s get the YAML for our deployment and service.
kubectl get deployment nginx-test -o yaml > nginx-test-deployment.yaml
kubectl get service nginx-test -o yaml > nginx-test-service.yaml
Now, edit nginx-test-deployment.yaml. We need to add a volume and volumeMounts section to the pod’s spec. We also need to modify the containers to use these mounts and configure Nginx.
Here’s an example of how you might modify the nginx-test-deployment.yaml. We’ll update the spec.template.spec to include:
spec:
volumes:
- name: tls-certs
secret:
secretName: my-tls-secret
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: tls-certs
mountPath: "/etc/nginx/ssl"
readOnly: true
# You'll need to add a command or config to tell Nginx to use these certs.
# For a quick test, you can override the default nginx command to run a script
# that configures nginx. Or, even simpler for demonstration, modify the image
# or use a custom nginx.conf.
# A more robust way is to provide a custom nginx.conf.
A simpler approach for local testing is to use an Ingress controller, which is designed to handle TLS termination. Minikube comes with an Ingress addon.
First, enable the Ingress addon:
minikube addons enable ingress
Once enabled, Minikube will deploy an Ingress controller. You can verify it’s running:
kubectl get pods -n kube-system | grep ingress
Now, we need to create an Ingress resource that points to our nginx-test service and uses the my-tls-secret.
Create a file named nginx-ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
# This annotation is crucial for Nginx Ingress Controller to use TLS
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
tls:
- hosts:
- minikube-local.com
secretName: my-tls-secret
rules:
- host: minikube-local.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-test
port:
number: 80
Apply this Ingress resource:
kubectl apply -f nginx-ingress.yaml
Now, you need to tell your local machine to resolve minikube-local.com to your Minikube IP. You can do this by editing your /etc/hosts file (on Linux/macOS) or C:\Windows\System32\drivers\etc\hosts (on Windows). Add the following line:
192.168.49.2 minikube-local.com
(Remember to replace 192.168.49.2 with the actual output of minikube ip).
Now, when you navigate to https://minikube-local.com in your browser, you should see the Nginx welcome page. Your browser will likely show a security warning because the certificate is self-signed. You’ll need to accept the risk to proceed.
The key insight here is that the Ingress controller acts as the TLS terminator. It takes the incoming HTTPS request, decrypts it using the certificate from my-tls-secret, and then forwards the request as plain HTTP to your nginx-test service. This is a common pattern for handling TLS termination in Kubernetes.
The next hurdle you’ll likely encounter is managing more complex certificate requirements, such as wildcard certificates or integrating with external certificate authorities for staging environments.