> ## Documentation Index
> Fetch the complete documentation index at: https://ubicloud.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Expose an Application Securely Using TLS

In this guide, we'll walk through the process of deploying a simple HTTP server secured with TLS and exposed via the Kubernetes Gateway API.

To securely deploy your applications on Ubicloud Kubernetes clusters using TLS, set up NGINX Gateway Fabric along with cert-manager. This setup handles all your TLS needs using the Gateway API.

Follow this step-by-step guide to deploy and expose an HTTPS application on your Kubernetes cluster.

### Prerequisites

To complete this tutorial, `kubectl` and `helm` must be installed. You can follow the official installation guides available on the [Kubernetes website](https://kubernetes.io/docs/tasks/tools/install-kubectl/) and [Helm website](https://helm.sh/docs/intro/install/)

You'll also need an active domain and access to the control panel for managing DNS records in order to complete this guide.

### Creating a Kubernetes Cluster

If you don't have a Kubernetes cluster yet, you can create one using Ubicloud. Follow the instructions in the [Quickstart Guide](https://www.ubicloud.com/docs/managed-kubernetes/quickstart) to set up your cluster and configure `kubectl` to access it.

### Installing the required addons

You'll need an email to register yourself with letsencrypt.

```bash theme={null}
export CLUSTER_ISSUER_EMAIL=email@yourcompany.com
```

Next, we'll install the Gateway API CRDs, NGINX Gateway Fabric, and cert-manager.

```bash wrap theme={null}
kubectl kustomize https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.5.1 | kubectl apply -f -

helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
  --create-namespace -n nginx-gateway

helm repo add jetstack https://charts.jetstack.io
helm repo update

helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --set crds.enabled=true \
  --set config.apiVersion="controller.config.cert-manager.io/v1alpha1" \
  --set config.kind="ControllerConfiguration" \
  --set config.enableGatewayAPI=true
```

We'll also create a ClusterIssuer in order to get certificates from letsencrypt for our service. Note the `gatewayHTTPRoute` solver, which tells cert-manager to use the Gateway API for HTTP-01 challenges.

```bash theme={null}
kubectl apply -f <(cat <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
 name: letsencrypt
spec:
 acme:
   server: https://acme-v02.api.letsencrypt.org/directory
   email: $CLUSTER_ISSUER_EMAIL
   privateKeySecretRef:
     name: letsencrypt
   solvers:
   - http01:
       gatewayHTTPRoute: {}
EOF
)
```

### Create a Gateway

First, create a `CNAME` record with your DNS provider pointing `*.somesubdomain.yourdomain.com` to the domain listed in the "Service URL" in the Overview page of your Kubernetes cluster in Ubicloud console. Feel free to use any subdomain that best suits your setup.

```bash theme={null}
export DOMAIN_SUFFIX=somesubdomain.yourdomain.com
```

Next, create a Gateway resource. NGINX Gateway Fabric will automatically provision a LoadBalancer Service and an NGINX data plane when a Gateway is created.

```bash theme={null}
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
  namespace: nginx-gateway
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    hostname: "hello-world.$DOMAIN_SUFFIX"
    port: 443
    protocol: HTTPS
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: hello-world-tls
EOF
```

Once the Gateway is created, a Service named `gateway-nginx` will appear in the default namespace. This Service is of type LoadBalancer, and the `EXTERNAL-IP` column will display a domain that resolves to the IPs of your worker nodes.

You can see this service using the command below

```bash theme={null}
kubectl -n nginx-gateway get service gateway-nginx
```

Here's a sample output of the command:

```
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP                                  PORT(S)                      AGE
gateway-nginx   LoadBalancer   10.105.61.236   devcluster-services-0b1c1.k8s.ubicloud.com   80:32271/TCP,443:30363/TCP   8m15s
```

#### Deploy the application, Service, and HTTPRoute

Now deploy a simple NGINX web server, expose it as a Service, and create an HTTPRoute to route external HTTPS traffic to it.

```bash theme={null}
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
 name: hello-world-deployment
spec:
 replicas: 1
 selector:
   matchLabels:
     app: hello-world
 template:
   metadata:
     labels:
       app: hello-world
   spec:
     containers:
     - name: hello-world
       image: nginx
       ports:
       - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
 name: hello-world-service
spec:
 selector:
   app: hello-world
 ports:
 - port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: hello-world
spec:
  parentRefs:
  - name: gateway
    namespace: nginx-gateway
    sectionName: https
  hostnames:
  - "hello-world.$DOMAIN_SUFFIX"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: hello-world-service
      port: 80
EOF
```

This creates three resources:

* **Deployment**: Runs an NGINX container that serves the default welcome page on port 80.
* **Service**: Exposes the Deployment inside the cluster so that the HTTPRoute can forward traffic to it.
* **HTTPRoute**: Attaches to the Gateway's `https` listener (via `sectionName: https`) and routes all requests for `hello-world.<your-domain>` to the `hello-world-service`. This is the resource that connects your external HTTPS traffic all the way to your application pods.

Now you can visit [https://hello-world.somesubdomain.yourdomain.com](https://hello-world.somesubdomain.yourdomain.com)!
