Configuring a Custom SSL Certificate on a Load Balancer
The Hostman load balancer supports custom SSL certificates stored as Kubernetes secrets of type kubernetes.io/tls. To enable HTTPS with your own certificate, create a TLS secret containing your certificate and private key, then reference it in the load balancer's annotations.
Create a TLS Secret Copy link
-
Download your certificate files from your CA.
-
Create a TLS secret in the same namespace as your load balancer:
kubectl -n <namespace> create secret tls my-app-tls \
--cert=crt.crt \
--key=key.key-
Verify the secret type:
kubectl -n <namespace> get secret my-app-tls -o yamlThe output should include:
type: kubernetes.io/tlsConfigure the Service Copy link
Add the following annotations to your load balancer manifest:
apiVersion: v1
kind: Service
metadata:
name: my-app
annotations:
k8s.hostman.com/attached-loadbalancer-ssl: "true"
k8s.hostman.com/attached-loadbalancer-ssl-type: "custom"
k8s.hostman.com/attached-loadbalancer-ssl-fqdn: "example.com"
k8s.hostman.com/attached-loadbalancer-ssl-secret-name: "my-app-tls"
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- name: https
port: 443
targetPort: 80
appProtocol: k8s.hostman.com/proto-https Annotation reference:
-
-
k8s.hostman.com/attached-loadbalancer-ssl: Enables SSL certificate support. -
k8s.hostman.com/attached-loadbalancer-ssl-type: Sets the certificate type. Usecustomfor your own certificate. -
k8s.hostman.com/attached-loadbalancer-ssl-fqdn: The domain name the certificate was issued for. -
k8s.hostman.com/attached-loadbalancer-ssl-secret-name: The name of the TLS secret containing the certificate and private key.
-
-
Apply the changes:
kubectl apply -f service.yamlVerify the Certificate Copy link
Run the following command to check which certificate the load balancer is serving:
echo | openssl s_client \
-connect example.com:443 \
-servername example.com \
2>/dev/null | openssl x509 -noout -subject -issuer -dates A successful result looks like this:
subject=CN=example.com
issuer=C=BE, O=GlobalSign nv-sa, CN=GlobalSign GCC R6 AlphaSSL CA 2025You can also verify the HTTPS connection using curl:
curl -kv https://example.comLook for the following in the output:
SSL certificate verify ok.And confirm your certificate details appear:
subject: CN=example.comIf you see the following instead:
subject: CN=emptyThat means the load balancer could not apply your certificate and has fallen back to the default one. Double-check your secret name and annotations.
Rotate the Certificate Copy link
To replace an existing certificate, update the secret in place:
kubectl -n <namespace> create secret tls my-app-tls \
--cert=new.crt \
--key=new.key \
--dry-run=client -o yaml | kubectl apply -f - After updating the secret, trigger a load balancer reconfiguration by touching any service annotation:
kubectl -n <namespace> annotate svc my-app \
k8s.hostman.com/rotate-ts="$(date +%s)" \
--overwriteThe Cloud Controller Manager (CCM) will re-read the secret and push the updated certificate to the load balancer.
Practical Example Copy link
This example walks you through configuring a custom SSL certificate on a test Nginx application.
Prerequisites: a domain name and a valid certificate issued by a trusted CA.
Create a Namespace Copy link
Create a dedicated namespace for testing:
kubectl create namespace test-namespaceDeploy the Test Application Copy link
-
Create a file called
nginx-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: test-namespace
spec:
replicas: 1
selector:
matchLabels:
app: nginx-custom-cert-test
template:
metadata:
labels:
app: nginx-custom-cert-test
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
-
Apply the manifest:
kubectl apply -f nginx-deployment.yaml-
Confirm the pod is running:
kubectl get pods -n test-namespaceCreate a Load Balancer Copy link
-
Create a file called
nginx-loadbalancer.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer
namespace: test-namespace
spec:
type: LoadBalancer
selector:
app: nginx-custom-cert-test
ports:
- name: https
port: 443
targetPort: 80
appProtocol: k8s.hostman.com/proto-https
-
Apply the manifest:
kubectl apply -f nginx-loadbalancer.yaml-
Wait for an external IP address to be assigned:
kubectl get svc nginx-loadbalancer -n test-namespace -wExample output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
nginx-loadbalancer LoadBalancer 10.101.130.253 203.0.113.10 443:31826/TCPConfigure DNS Copy link
-
Create an A record for your domain pointing to the load balancer's external IP.
-
Confirm the domain resolves correctly:
dig +short example.comThe output should return the load balancer's IP address.
Create the TLS Secret Copy link
-
Create the TLS secret in the same namespace as your service:
kubectl -n test-namespace create secret tls my-app-tls \
--cert=crt.crt \
--key=key.key-
Verify the secret was created correctly:
kubectl -n test-namespace get secret my-app-tls -o yamlThe output should include:
type: kubernetes.io/tls-
Optionally, inspect the certificate directly from the secret:
kubectl -n test-namespace get secret my-app-tls \
-o jsonpath='{.data.tls\.crt}' \
| base64 -d \
| openssl x509 -noout -subject -issuer -datesApply the Certificate to the Load Balancer Copy link
-
Add the SSL annotations to your
nginx-loadbalancer.yamlmanifest:
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer
namespace: test-namespace
annotations:
k8s.hostman.com/attached-loadbalancer-ssl: "true"
k8s.hostman.com/attached-loadbalancer-ssl-type: "custom"
k8s.hostman.com/attached-loadbalancer-ssl-fqdn: "example.com"
k8s.hostman.com/attached-loadbalancer-ssl-secret-name: "my-app-tls"
spec:
type: LoadBalancer
selector:
app: nginx-custom-cert-test
ports:
- name: https
port: 443
targetPort: 80
appProtocol: k8s.hostman.com/proto-https
-
Apply the updated manifest:
kubectl apply -f nginx-loadbalancer.yaml-
Verify the service annotations are set:
kubectl -n test-namespace get svc nginx-loadbalancer -o yamlThe annotations section should include:
k8s.hostman.com/attached-loadbalancer-ssl: "true"
k8s.hostman.com/attached-loadbalancer-ssl-type: custom
k8s.hostman.com/attached-loadbalancer-ssl-fqdn: example.com
k8s.hostman.com/attached-loadbalancer-ssl-secret-name: my-app-tls Once the CCM has successfully read the certificate, a hash annotation will appear:
k8s.hostman.com/attached-loadbalancer-ssl-cert-hash: ...This confirms the certificate has been picked up from the secret.
Verify the Application Copy link
Open your domain in a browser. If the certificate was applied correctly, the browser will establish a secure HTTPS connection without any warnings.
You can also test with curl:
curl -I https://example.comA successful response confirms that:
-
the certificate has been loaded onto the load balancer;
-
the HTTPS connection is established correctly;
-
the load balancer is forwarding requests to your application running in Kubernetes.
Clean Up Copy link
When you're done testing, delete the namespace to remove all associated resources, including the Deployment, Service, and TLS secret:
kubectl delete namespace test-namespace