
Nginx Ingress Controller is a popular Kubernetes Ingress controller that uses Nginx as a reverse proxy and load balancer to securely route external traffic to services in a cluster. It works as the single access point for underlying services while offering SSL/TLS termination, load balancing, session handling, and path-based routing for services in the Kubernetes cluster.
In this article, you will set up a Nginx Ingress Controller with SSL in a Kubernetes Engine cluster. You will deploy two applications and issue Let’s Encrypt certificates with Cert Manager to secure them. You will also see how you can import commercial SSL certificates for TLS encryption.
Prerequisites
Before you begin, make sure you:
- Have a Kubernetes cluster with at least 2 nodes.
- Install Kubectl to access your Kubernetes cluster.
- Install the Helm Package Manager on your computer.
- Have a Domain name. For example,
example.com
.
Install the Nginx Ingress Controller
Add the Nginx Ingress repository.
console$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
Update Helm.
console$ helm repo update
Install the Nginx Ingress Controller.
console$ helm install ingress-nginx ingress-nginx/ingress-nginx
After installation, a Load Balancer is automatically added to your cluster.
console$ kubectl get services ingress-nginx-controller
Output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx-controller LoadBalancer 10.101.22.249 <pending> 80:31915/TCP,443:30217/TCP 106s
It may take some time for the service to get an
EXTERNAL-IP
, depending on your cloud provider.
Install CertManager
Install the latest CertManager version.
console$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml
Visit the official CertManager releases page to get the latest version.
Inspect the CertManager Kubernetes resources.
console$ kubectl get all -n cert-manager
You should see multiple resources of kind pod, service, replicaset, and deployment, all related to your CertManager.
Deploy Backend Applications
In this section, you'll deploy example applications to test your Nginx Ingress controller. For purposes of this article, deploy two example applications, app1
and app2
using the http-echo image that outputs the command line argument on a html page.
Create a manifest file
app1-deploy.yaml
for Deploymentapp1
.console$ nano app1-deploy.yaml
Add the following content to the file.
yamlapiVersion: apps/v1 kind: Deployment metadata: name: app1 spec: replicas: 1 selector: matchLabels: app: app1 template: metadata: labels: app: app1 spec: containers: - name: app1 image: hashicorp/http-echo args: ["-text=Hello from App1"] ports: - containerPort: 5678
Save and close the file.
Create the second manifest file
app2-deploy.yaml
for Deploymentapp2
.console$ sudo nano app2-deploy.yaml
Add the following content to the file.
yamlapiVersion: apps/v1 kind: Deployment metadata: name: app2 spec: replicas: 1 selector: matchLabels: app: app2 template: metadata: labels: app: app2 spec: containers: - name: app2 image: hashicorp/http-echo args: ["-text=Hello from App2"] ports: - containerPort: 5678
Save and close the file.
Apply the manifest for the
app1
deployment.console$ kubectl apply -f app1-deploy.yaml
Apply the manifest for the
app2
deployment.console$ kubectl apply -f app2-deploy.yaml
Verify that your deployments are successful.
console$ kubectl get deployments
Your should see the
app1
andapp2
deployments listed.Create a new
app1-svc.yaml
service manifest.console$ nano app1-svc.yaml
Add the following content to the file.
yamlapiVersion: v1 kind: Service metadata: name: app1-svc spec: ports: - name: http port: 80 targetPort: 8080 selector: app: app1
Save and close the file.
Create another service manifest file
app2-svc.yaml
.console$ nano app2-svc.yaml
Add the following content to the file.
yamlapiVersion: v1 kind: Service metadata: name: app2-svc spec: ports: - name: http port: 80 targetPort: 8080 selector: app: app2
Save and close the file.
Deploy the
app1-svc
service.console$ kubectl apply -f app1-svc.yaml
Deploy the
app2-svc
service.console$ kubectl apply -f app2-svc.yaml
Verify that all services are running.
console$ kubectl get services
Your should see the
app1-svc
andapp2-svc
services listed.
Setup DNS Records
Login to your DNS Provider account. For example, Vultr DNS.
Access your domain.
Set up a new domain A subdomain record with the value
app1
that points to your LoadBalancer’s external IP Address.Set up another A subdomain record with the value
app2
that points to the same IP Address.
Configure the Nginx Ingress Controller to Expose backend Applications
In this section, you'll create Ingress resources for both the applications in the cluster and test them.
Create a new manifest file
app1-ingress.yaml
to create an Ingress resource forapp1
Deployment.console$ sudo nano app1-ingress.yaml
Add the following content to the file.
yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-app1 annotations: cert-manager.io/issuer: letsencrypt-nginx spec: ingressClassName: nginx rules: - host: app1.example.com http: paths: - pathType: Prefix path: "/" backend: service: name: app1-svc port: number: 80
Replace
app1.example.com
with your domain name. Save and close the file.Create another manifest file
app2-ingress.yaml
to create an Ingress resource forapp2
Deployment.console$ sudo nano app2-ingress.yaml
Add the following content to the file.
yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-app2 annotations: cert-manager.io/issuer: letsencrypt-nginx spec: ingressClassName: nginx rules: - host: app2.example.com http: paths: - pathType: Prefix path: "/" backend: service: name: app2-svc port: number: 80
Replace
app2.example.com
with your domain name. Save and close the file.Apply the manifest for the
ingress-app1
Ingress resource.console$ kubectl apply -f app1-ingress.yaml
Apply the manifest for the
ingress-app2
Ingress resource.console$ kubectl apply -f app2-ingress.yaml
Verify that the Ingress resources are available.
console$ kubectl get ingress
You should see the
ingress-app1
andingress-app2
Ingress resources listed. Wait for theADDRESS
column of the output to get its value, which should be the same as the IP address of your load balancer.
Setup Nginx Ingress Controller to Use Production-Ready SSL Certificates
You can set up the Nginx Ingress controller to use SSL certificates for your cluster services using an Issuer resource for CertManager. CertManager creates Custom Resource Definitions (CRDs) to handle the certificate issuance process from a Certificate Authority (CA) such as Let’s Encrypt, and these include the following:
- Issuer: Defines an issuer configuration such as the type of issuer like ACME, method of certificate issuance like DNS01 or HTTP01, and the necessary credentials in a single namespace.
- Cluster Issuer: Functions like Issuer but can issue certificates to any namespace within the Kubernetes cluster. It’s important when using the same issuer configuration across multiple namespaces.
- Certificate: Defines a namespaced resource with the desired properties of a TLS/SSL certificate such as the domain names, associated secrets to store the certificate, and the trusted CA issuer to use. The certificate must reference an Issuer or Cluster Issuer resource.
In this section, you'll set up the Nginx Ingress Controller to use trusted SSL certificates issued by CertManager.
Inspect the available CRDs by running the following command.
console$ kubectl get crd -l app.kubernetes.io/name=cert-manager
Your output should contain resources related to CertManager, such as
issuers.cert-manager.io
,certificates.cert-manager.io
,clusterissuers.cert-manager.io
, and a few more.
Setup Let’s Encrypt Certificates
Create a new issuer manifest. For example,
cert-issuer.yaml
.console$ nano cert-issuer.yaml
Add the following configuration to the file.
yamlapiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt-nginx spec: acme: email: hello@example.com server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-nginx-prod solvers: - http01: ingress: class: nginx
The above configuration uses the ACME issuer with the following fields:
- email: Active email address to associate with the ACME account. Do not specify a
@example.com
email because it would not allow the issuer resource to become active. - server:: URL to access the ACME Let’s Encrypt server endpoint.
- privateKeySecretRef: name: Kubernetes secret to store the generated ACME account private key.
- solvers: Defines the certificate issuer challenge. You can use the
http01
challenge or thedns01
challenge. It’s recommended to use thehttp01
challenge unless issuing wildcard certificates.
Enter your email address to replace the pre-filled value, then save and close the file.
- email: Active email address to associate with the ACME account. Do not specify a
Apply the issuer resource to your cluster.
console$ kubectl apply -f cert-issuer.yaml
Verify that the issuer resource is available and ready to use.
console$ kubectl get issuer
Your output should look like the one below.
NAME READY AGE letsencrypt-nginx False 4s
The issuer's READY value is
False
. After some time, the status changes toTrue
.To configure the Ingress controller to map hosts with TLS, follow the steps below:
Check the state of your Ingress resources.
console$ kubectl get ingress
Edit the
app1-ingress.yaml
file you created earlier.console$ nano app1-ingress.yaml
Add the following
spec.tls
section to the file:yamltls: - hosts: - app1.example.com secretName: letsencrypt-nginx-app1
The manifest should look like:
yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-app1 annotations: cert-manager.io/issuer: letsencrypt-nginx spec: ingressClassName: nginx rules: - host: app1.example.com http: paths: - pathType: Prefix path: "/" backend: service: name: app1-svc port: number: 80 tls: - hosts: - app1.example.com secretName: letsencrypt-nginx-app1
Save and close the file.
Similarly, edit the
app2-ingress.yaml
file and add the following content to the manifest file.yamltls: - hosts: - app1.example.com secretName: letsencrypt-nginx-app2
Apply the configurations to enable TLS on each of the hosts.
console$ kubectl apply -f app1-ingress.yaml
console$ kubectl apply -f app2-ingress.yaml
Verify that your Ingress resources have the TLS port
443
activated under the PORTS column.console$ kubectl get ingress
Output:
NAME CLASS HOSTS ADDRESS PORTS AGE app1-ingress nginx app1.example.com 192.0.2.1 80,443 10m app2-ingress nginx app2.example.com 192.0.2.1 80,443 10m
Verify that the certificate resources are available.
console$ kubectl get certificates
Your output should look like the one below.
NAME READY SECRET AGE letsencrypt-app1 True letsencrypt-nginx-app1 5m letsencrypt-app2 True letsencrypt-nginx-app2 5m
If the READY column returns
True
, your Let’s Encrypt certificates are successfully propagated. IfFalse
, please check your Ingress resource configuration and reapply changes to request a new certificate.
Test the SSL Configuration
Depending on your SSL certificate deployment method, verify that you can securely access your services over HTTPS using a web browser of your choice.
https://app1.example.com
https://app2.example.com
If you try to access your hosts over HTTP, the Ingress controller automatically redirects your request to HTTPS.
Import Commercial SSL Certificates
To import commercial SSL certificates purchased from a trusted certificate authority (CA), convert the certificate and private key to the base64
format, add them to a Kubernetes secret, and then configure your Ingress resources to use the certificates.
Convert the commercial SSL certificate and private key to base64. Copy the resultant values to your clipboard.
console$ base64 -w 0 /path/ssl-certificate.pem
console$ base64 -w 0 /path/cert-private-key.pem
Replace /path with the actual directory path to your commercial SSL certificate and private key.
Create a new Kubernetes secrets manifest.
console$ nano ssl-secret.yaml
Add the following configurations to the file.
yamlapiVersion: v1 kind: Secret metadata: name: prod-ssl-secret type: kubernetes.io/tls data: tls.crt: <paste-base64-values> tls.key: <paste-base64-values>
Paste your base64 encoded values to the respective fields as follows:
tls-crt:
SSL certificate in base64tls.key:
Certificate private key in base64
Save and close the file.
To configure Nginx to use your commercial SSL certificate, mention the above Secret resource name in your Ingress resource's
spec.tls.secretName
field.
Troubleshooting
Nginx 502 Gateway Error:
Verify that your Ingress configuration is correct and the referenced services are available and running.
Unable to generate Let’s Encrypt Certificates,
READY
column remainsFalse
:- Verify that your Issuer and Certificate configurations are correct.
- Provide a valid email address.
- Check the Issuer resource Logs for further troubleshooting.
Conclusion
In this article, you have installed and set up the Nginx Ingress Controller with SSL on a Vultr Kubernetes Engine (VKE) cluster. You can use the controller to route external requests to cluster services securely over HTTPS.
No comments yet.