Deploy with k8s
On this page
Kubernetes is an extensible and open-source container-orchestration system used for automating application deployments. Some of the most notable features it provides include self-healing, auto-scaling, and automated rollouts and rollbacks.
Since the Kubernetes container runtime supports Docker, FusionAuth Docker containers can be deployed to any Kubernetes cluster.
The following guide demonstrates how to deploy FusionAuth containers using kubectl, the Kubernetes command-line tool that enables you to send commands to a cluster through the API server. You'll need a cluster running to work through this guide.
Requirements#
kubectl- Command line tool that interacts with the Kubernetes API server and is useful for managing Kubernetes clusters. Before proceeding, follow the installation documentation that corresponds to your platform. This guide uses version1.37.helm- Package manager used for installing and managing Kubernetes applications. In this guide, you will be using a Helm chart to install FusionAuth on our Kubernetes cluster. For more information, see Installing Helm. This guide uses version4.3.- An available Kubernetes cluster running version
1.23or later. If you need to set up a cluster, we have provided the below installation guides for both local development environments and the major cloud providers. Each provides step-by-step instructions intended to get you up and running as fast as possible.
Adding the Helm Chart Repository#
To get started, the first thing to do is add the FusionAuth Helm Chart repository. This can be done with the following.
helm repo add fusionauth https://fusionauth.github.io/chartsTo view the list of repositories that you have added use the following command:
helm repo listNAME URL
fusionauth https://fusionauth.github.io/charts
To search repositories:
helm search repo fusionauthNAME CHART VERSION APP VERSION DESCRIPTION
fusionauth/fusionauth 1.69.4 1.69.4 Helm chart for FusionAuth
Helm Chart Configuration#
Before you install, create a values.yaml file that holds the chart values you want to change. Helm merges this file with the chart's defaults, so it only needs the values that differ. This guide covers the values you must set to deploy FusionAuth.
To review every option and its default, save the chart's default values to a separate file:
helm show values fusionauth/fusionauth > chart-values.yamlReplicas#
The replicaCount value indicates the number of instances of FusionAuth to run in a ReplicaSet. Kubernetes will monitor the cluster to ensure that this number of instances of FusionAuth is running at all times.
By default, the replicaCount value is set to 1 which typically works well for development and testing environments, but you will likely want to adjust this based on your system and application requirements.
# replicaCount -- The number of fusionauth-app instances to run
replicaCount: 1FusionAuth Version#
Each chart release sets image.tag to the FusionAuth version it was released with, so helm install installs that version. To run a different version, set image.tag in values.yaml to one of the FusionAuth releases. Use a specific version instead of latest, so every pod runs the same release.
Extra Containers#
You may want to inject a sidecar or ambassador container.
This is useful if you want to, for instance, proxy requests to FusionAuth to put it at a different path or limit the IP addresses which have access to the administrative user interface.
You can do this with the extraContainers value.
Containers defined here will be added to the FusionAuth pod.
extraContainers:
- name: my-sidecar
image: nginx:stableYou can find community contributed proxy configurations here.
Database Configuration#
Now, configure the database connection. Each of our FusionAuth pods will use this configuration when communicating with the database.
FusionAuth requires an external database and, optionally an external Elasticsearch cluster. Setting these up is outside of the scope of this document.
Consult the setup guides for instructions for AWS, GCP, and more.
Store the database passwords in Kubernetes Secrets rather than in values.yaml, so they stay out of version control and your Helm release history. Create one Secret for the password FusionAuth uses in normal operation, and one for the database superuser password FusionAuth uses to create its database:
kubectl create secret generic fusionauth-db-credentials --from-literal=password='<fusionauth-user-password>'
kubectl create secret generic fusionauth-db-root-credentials --from-literal=password='<superuser-password>'Then add a database section to values.yaml with your database host and user names, and reference the Secrets:
database:
host: "<database-host>"
port: 5432
protocol: postgresql
tls: true
tlsMode: require
name: fusionauth
dbUser:
username: fusionauth
existingSecret:
enabled: true
name: fusionauth-db-credentials
passwordKey: password
rootUser:
username: "<superuser-name>"
existingSecret:
enabled: true
name: fusionauth-db-root-credentials
passwordKey: passwordDuring initial setup, FusionAuth uses the rootUser credentials to create the fusionauth database and the dbUser user. If you'd rather set up the database yourself, follow the advanced database installation guide, then remove the rootUser section and its Secret.
The tlsMode: require setting encrypts the database connection, but doesn't verify the database server's certificate. To verify it, mount your database provider's CA certificate into the pod with extraVolumes and extraVolumeMounts, and set database.url to a full JDBC URL that uses sslmode=verify-full. See database.url in the configuration reference for an example. When database.url is set, the chart ignores tls and tlsMode.
Search Configuration#
If search.engine is set to elasticsearch, add a search section to values.yaml with your search host. Use https if your search service supports it. If your search service doesn't require a username and password, leave out basicAuth:
search:
engine: elasticsearch
protocol: https
host: "<search-host>"
port: 9200
basicAuth:
existingSecret:
enabled: true
name: fusionauth-search-credentials
userKey: username
passwordKey: passwordStore the search credentials in a Secret, like the database passwords:
kubectl create secret generic fusionauth-search-credentials --from-literal=username='<search-username>' --from-literal=password='<search-password>'Runtime and Silent Mode#
Set the runtime mode to production and turn on silent mode. In silent mode, FusionAuth creates its database on first start and applies database migrations when you update it, without waiting for someone to complete Maintenance Mode in a browser:
app:
runtimeMode: production
silentMode: trueDeploy FusionAuth To the Cluster#
Now that values.yaml is ready, it is time to install the chart on the cluster. The helm install command is used to install a chart by name and can be applied using the syntax:
helm install [CHART NAME] [CHART] [flags]
Here you will install a chart including the -f flag to override the default values.
helm install my-release fusionauth/fusionauth -f values.yamlYou can override values in the values.yaml file that you pass when installing a chart, or with the --set flag on the command line.
Using --set can be useful when developing scripts or command line tools. Either method is acceptable.
If the previous command was successful, you should see output similar to the following:
NAME: my-release
LAST DEPLOYED: Tue Nov 3 13:26:58 2026
NAMESPACE: default
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
export SVC_NAME=$(kubectl get svc --namespace default -l "app.kubernetes.io/name=fusionauth,app.kubernetes.io/instance=my-release" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:9011 to use your application"
kubectl port-forward svc/$SVC_NAME 9011:9011
You can get the status of your deployment with kubectl.
kubectl get deployments -o wideNAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
my-release-fusionauth 1/1 1 1 21s fusionauth docker.io/fusionauth/fusionauth-app:1.69.4 app.kubernetes.io/instance=my-release,app.kubernetes.io/name=fusionauth
As instructed by the success message output above, you can create a proxy enabling you to connect to the cluster from localhost:
export SVC_NAME=$(kubectl get svc --namespace default -l "app.kubernetes.io/name=fusionauth,app.kubernetes.io/instance=my-release" -o jsonpath="{.items[0].metadata.name}")
kubectl port-forward svc/$SVC_NAME 9011:9011Forwarding from 127.0.0.1:9011 -> 9011
Navigate to http://localhost:9011 and you will land on the FusionAuth Setup Wizard. For a complete tutorial walking you through the initial FusionAuth configuration, see Setup Wizard & First Login.

Expose FusionAuth Through a Gateway#
To let users reach FusionAuth from outside the cluster, route traffic to it with the Gateway API, the Kubernetes API for bringing external traffic into a cluster. The FusionAuth chart can create the route for you.
A Gateway needs a controller that implements it. This guide uses Envoy Gateway. Most cloud providers also offer an implementation, such as the GKE Gateway controller. To use another implementation, install it instead of Envoy Gateway and use its GatewayClass in gateway.yaml.
Install Envoy Gateway#
Install Envoy Gateway, which also installs the Gateway API resource definitions:
helm install eg oci://docker.io/envoyproxy/gateway-helm --version v1.9.3 -n envoy-gateway-system --create-namespaceThen wait until it is ready:
kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-gateway --for=condition=AvailableCreate the Gateway#
The Gateway terminates TLS, so it needs a certificate for your FusionAuth hostname. Store the certificate and private key in a TLS Secret, or use cert-manager to issue and renew one:
kubectl create secret tls fusionauth-tls --cert=tls.crt --key=tls.keyNext, create a file named gateway.yaml with the following resources:
- A
GatewayClassthat assigns Gateways of the classegto Envoy Gateway. - A Gateway with an HTTPS listener that uses your TLS Secret, and an HTTP listener.
- An
HTTPRoutethat redirects every HTTP request to HTTPS.
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: fusionauth-gateway
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
hostname: auth.example.com
- name: https
protocol: HTTPS
port: 443
hostname: auth.example.com
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: fusionauth-tls
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: fusionauth-http-redirect
spec:
parentRefs:
- name: fusionauth-gateway
sectionName: http
hostnames:
- auth.example.com
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301Replace auth.example.com with your FusionAuth hostname, then apply the file:
kubectl apply -f ./gateway.yamlRoute Traffic to FusionAuth#
Add a gateway section to values.yaml, using the same hostname. The chart then creates an HTTPRoute that sends requests from the Gateway's HTTPS listener to FusionAuth:
gateway:
enabled: true
parentRefs:
- name: fusionauth-gateway
sectionName: https
hostnames:
- auth.example.comApply the change by upgrading the release:
helm upgrade my-release fusionauth/fusionauth -f values.yamlFinally, get the Gateway's external address:
kubectl get gateway fusionauth-gatewayNAME CLASS ADDRESS PROGRAMMED AGE
fusionauth-gateway eg 203.0.113.10 True 2m
Point the DNS record for your FusionAuth hostname at the address in the ADDRESS column. On a cloud provider, this is the address of a load balancer that Envoy Gateway created for the Gateway.
If you have completed this tutorial using minikube, you can give the Gateway an address by creating a network route to your cluster with the command minikube tunnel. For documentation on this, see Using minikube tunnel.
Congratulations! You now have a fully functional Kubernetes environment running FusionAuth.
Troubleshooting#
Runtime Mode Mismatch#
If you receive a message similar to this one in your system log:
ERROR io.fusionauth.api.service.system.NodeService - Node [c98263dc-7f12-4879-93c1-f1a634912a51] cannot be added. The runtime mode is [Development] and this node in [Production] mode.
This means that your nodes are in different runtime modes. This will not work and may cause undetermined behavior. All nodes of a FusionAuth cluster must be running in the same mode, either Production or Development.
To resolve this issue, take the following steps:
- Stop all existing nodes, whether they are running as containers or processes.
- Review configuration to confirm that all nodes are configured with the same runtime mode.
- Restart the nodes.
Next Steps#
Before customers log in to this instance, see Harden a Production Instance for the FusionAuth settings to change, and the Kubernetes security documentation to secure the cluster itself.
To learn more about Kubernetes, here are a few recommended links to help you administer your cluster.
Related
Learn how to provision an AKS cluster in Microsoft Azure.
Learn how to provision an EKS cluster in AWS.
Learn how to provision a GKE cluster in Google Cloud (GCP).
Learn how to deploy and test FusionAuth using Kubernetes.