Find out how you can expand beyond the default URL given to each function in OpenFaaS with the new FunctionIngress CRD.

In this tutorial I’ll show you how to use the new FunctionIngress Custom Resource Definition (CRD) along with a new Kubernetes Operator to get Custom Domains for any OpenFaaS function deployed on Kubernetes.

How it works

First of all, we install the new Kubernetes Operator called “IngressOperator”. This Operator is responsible for translating CRD entries called FunctionIngress into two separate resources in the cluster: an Ingress definition and a TLS Certficate. The TLS Certificate is optional, and created by cert-manager by adding special annotations to the generated Ingress definition.

I built the IngressOperator to automate some of the tasks end-users of the project were using to deploy pretty-URLs for their static websites, APIs and functions with OpenFaaS. The first time I wrote about the Operator was in the Insiders Update for 2019-07-05.

Insiders Updates are exclusives updates containing my tutorials, projects, videos, links and industry info such as developments in Kubernetes. By Becoming an Insider 👑, you support my unpaid-OSS work and the OpenFaaS community. 🏆


To run through the tutorial, you will need to have some software set up already and a Kubernetes cluster with a public LoadBalancer service. If your Kubernetes services does not have a public LoadBalancer, install the IngressController using host ports.


  • Kubernetes

You need to have a Kubernetes cluster. I recommend using DigitalOcean Kubernetes for an easy and cost-efficient set-up.

Get free credits

  • helm

You’ll need helm for most of the components we are using. If you are allergic to helm’s server-side component called “tiller”, then don’t worry. You can simply use the “helm template” command to generate plain YAML files.

Install helm

  • OpenFaaS via helm

Install OpenFaaS via helm

You should also install the OpenFaaS CLI using the instructions at

  • The IngressController

Nginx, Traefik and Zalando’s Skipper are currently supported, if you have a request for another controller, then raise an issue.

In this tutorial I’ll be using Nginx, install with the following:

helm install stable/nginx-ingress --name nginxingress --set rbac.create=true
  • cert-manager (optional)

Using TLS is optional, but highly recommended and I will be setting it up today.

Follow the steps for “Install cert-manager” and “Configure cert-manager” from the OpenFaaS documentation here.

Note: You can skip the steps for creating a Certificate and Ingress entry for the gateway.

Deploy IngressOperator

We’ll now deploy the IngressOperator.

You’ll need to find your values.yaml file for the OpenFaaS Helm chart, then add:

  create: true

Then run a helm upgrade --install as per the Helm chart README.

Create a static website

We can use the Nginx static website template to create a function or microservice. Once deployed, we’ll move on to creating its custom domain name entry and then a CRD entry for it.

export OPENFAAS_PREFIX=alexellis2

faas template pull
faas new --lang static-site-nginx my-homepage --prefix ${OPENFAAS_PREFIX}

Set OPENFAAS_PREFIX with your own Docker Hub username, or private registry address and repo.

Create the homepage:

echo "<html>Hello world</html>" > ./my-homepage/index.html

The following will build a container image, push it to the remote registry and then deploy it to OpenFaaS, resulting in a static-website.

faas-cli up -f my-homepage.yml

Your traditional URL will appear on:

faas-cli describe -f my-homepage.yml my-homepage

Name:                my-homepage
Status:              Ready
Replicas:            1
Available replicas:  0
Invocations:         0
Image:               alexellis2/my-homepage:latest
Function process:    
Async URL: 
Labels:              faas_function : my-homepage

We’ll now create a DNS entry and then the custom hostname mapping and TLS certificate along with that.

Create a DNS A record for your sub-domain

My testing domain is and it cost me a very minimal amount of money from I can create sub-domains for each function, or for any testing that I do. If you are familiar with DNS-management, then create an A record for the IP address of the LoadBalancer created by Nginx.

kubectl get svc
NAME                                         TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                      AGE
nginxingress-nginx-ingress-controller        LoadBalancer   80:32126/TCP,443:30028/TCP   32d

You can see my external IP listed as

As a DigitalOcean customer, I can now use the DigitalOcean UI or CLI to create a DNS A record for Here is an example using the doctl CLI:

doctl compute domain create --ip-address

Domain                     TTL    0

Here’s an example of what that may look like within the UI:

Map the Custom Domain with a FunctionIngress

Now we will map the Custom Domain to the function using a FunctionIngress definition.

Save the following in a YAML file my-homepage-fni.yaml:

kind: FunctionIngress
  name: my-homepage-tls
  namespace: openfaas
  domain: ""
  function: "my-homepage"
  ingressType: "nginx"
    enabled: true
      name: "letsencrypt-prod"
      kind: "Issuer"
  • For the name I used a convention of the function’s name plus a suffix of -tls if using TLS.

  • Edit the domain to point as your own DNS A record or sub-domain

  • For the issuerRef, you can use the -staging or -prod issuer which you set up earlier using the OpenFaaS docs.

Now apply the file with kubectl apply -f my-homepage-fni.yaml

Check what happened

We already have a URL to access our static website, but after having created the FunctionIngress, we’ll get a HTTPS URL too.

This is what happens:

  • The CRD is detected and an Ingress record is created
  • The Ingress record is decorated with information about TLS
  • CertManager detects the TLS information using something called IngressShim
  • CertManager creates the TLS certificate

Check the ingress:

kubectl get ingress -n openfaas

NAME              HOSTS                      ADDRESS        PORTS     AGE
my-homepage-tls   80, 443   46s

Now check the certificate:

kubectl get cert -n openfaas

NAME                          READY   SECRET                               AGE
my-homepage-tls-certificate   true    my-homepage-tls-certificate-secret   2m37s

Note, if it appears as “Not Ready” for a long time, you can debug it with: kubectl describe cert/my-homepage-tls-certificate -n openfaas

The objects above were created automatically, so they will be deleted or edited if you delete or edit the FunctionIngress custom resource.

You can find out what happened inside the Operator by checking its logs:

kubectl logs -n openfaas deploy/ingress-operator

Try out your brand new Custom Domain

Congratulations! You can now create Custom Domains for any of your functions or microservices deployed with OpenFaaS, and add TLS too.

You can also drill-down into your certificate to check that it’s valid and when it will expire. Fortunately cert-manager will automatically renew the certificate for you on a regular basis.

Changing versions

We can now create a dedicated URL for anything we deploy through OpenFaaS. There’s nothing to stop you deploying multiple names for the same function to create an alias or versioned endpoint.

If we were to deploy a new version of our function (my-homepage-v2), we could deploy a new FunctionIngress record, or simply edit the object in Kubernetes via kubectl. The result is that the Ingress record will be edited to point at the new function without deleting or re-issuing a new Certificate.

kind: FunctionIngress
  name: my-homepage-tls
  namespace: openfaas
  domain: ""
  function: "my-homepage-v2"
  ingressType: "nginx"
    enabled: true
      name: "letsencrypt-prod"
      kind: "Issuer"

Connect & Learn

I hope you enjoyed the tutorial for the IngressOperator and FunctionIngress CRD. In the next post the community will show you how to combine this blog post with OpenFaaS Cloud and a template for Hugo to generate static websites from markdown. This would be great for hosting documentation, blogs and much more.

The code is available to star/fork or browse on GitHub: openfaas-incubator/ingress-operator.

If you have any comments, questions or suggestions, then please connect with me and the OpenFaaS community on Slack:

You can follow @alexellisuk on Twitter for more blogs, videos, tips and tutorials

Alex Ellis

Founder of @openfaas.