Skip to main content

Overview

FusionAuth is a self-hosted identity and access management platform: a user store with hosted login and registration pages, OAuth2 and OpenID Connect token issuance, SAML, MFA, and federation to external identity providers, managed through a browser admin UI. This template deploys one FusionAuth node together with a bundled PostgreSQL database that it creates, wires up and waits for — there is no database or secret to prepare before installing. The FusionAuth workload is publicly reachable by default so that applications can redirect users to it, and it keeps no state of its own: every user, tenant and application lives in the bundled database.
This template deploys into an existing GVC that you already have. It does not create or manage a GVC.

What Gets Created

Prerequisites

None for a default install. The bundled database’s credentials secret is created by the chart from your values, so there is nothing to create beforehand. Backups are optional and need a bucket plus a Control Plane cloud account — see Backing Up.

Installation

Install the chart from the marketplace registry, choosing the bundled database password — it is used exactly as given and is baked into the database the first time it starts:
Secret names are org-wide, so when you install a second FusionAuth release in the same org also set --set postgres.config.credentialsSecretName= to a name of your own; see Configuration. Or follow the instructions for your preferred method:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

Each block below is the shipped default for that part of values.yaml.

Image and Resources

The image is a Control Plane-published build of FusionAuth 1.60.2 that includes the PostgreSQL client used by the start script. The block exposes only limits, so the names are the platform’s own cpu and memory.

Firewall

  • firewall.external.inboundAllowCIDR — who can reach the login pages and admin UI from the internet. Open to everyone by default; restrict it to your own address range while you complete the setup wizard if you cannot do so immediately after installing.
  • firewall.external.outboundAllowCIDR — egress is closed by default. Any external identity provider (Google, Microsoft, a remote SAML IdP), outbound email and webhooks to internet destinations need this opened — 0.0.0.0/0 or the provider’s address ranges.
  • firewall.internal.type — which workloads in your org can reach port 9011 directly:
A firewall change can take a few minutes to take effect — re-test before concluding it did not apply.

Bundled PostgreSQL

The database is the PostgreSQL template deployed as a dependency. Unlike a standalone PostgreSQL install, this chart creates the credentials secret for you from the three values under postgres.credentials and hands the database its name, so the keys below are values rather than a secret you create.
  • postgres.credentials.* — applied only when the volume is first initialized. Changing them afterwards changes the secret but not the database; see Rotating the Database Password. username and database ship as username and test and are deliberately left alone across upgrades because an existing data directory was initialized with them; database also forms the JDBC URL FusionAuth connects with.
  • postgres.config.credentialsSecretName — the name of the dictionary secret the chart creates. Secret names are org-wide, so a second FusionAuth release left on the default is refused at install (the secret is owned by the first release) and creates nothing — the first release is untouched.
  • postgres.internalAccess.type — which workloads can reach port 5432. The default same-gvc is what the FusionAuth workload needs; none would cut it off from its own database.
  • postgres.resources — on a stateful workload maxCpu may not exceed four times minCpu; raising one without the other is rejected when the workload is applied.
There is no high-availability database option in this template: the dependency is the single-instance postgres template. A node failure reschedules the server and reattaches the same volume, so the exposure is minutes of downtime, not data loss.

PostgreSQL Backup

A cron workload runs pg_dumpall on the schedule and uploads a gzip-compressed SQL dump of the database to your bucket, authenticating with the username and password the chart wrote into the credentials secret. Provider setup steps are under Backing Up.
postgres.backup.image must match the server’s major version: tag 18.1.0 for postgres:18, 17.1.0 for postgres:17. Backups require PostgreSQL 17 or later.

Connecting

Complete the setup wizard immediately after installing. Inbound traffic is open to 0.0.0.0/0 by default and FusionAuth has no administrator until the wizard is finished, so whoever reaches the endpoint first creates that account. If you cannot do it right away, install with firewall.external.inboundAllowCIDR restricted to your own address and widen it afterwards.
Read the public endpoint from the workload, then confirm FusionAuth is up — /api/status answers 200 without an API key once the node is serving:
Give browser-facing applications the public address (authorization and login redirects must be reachable by the user’s browser), and give server-side code inside the GVC the internal address for token exchange and API calls. The OpenID Connect discovery document is at /.well-known/openid-configuration on either host, and at /TENANT_ID/.well-known/openid-configuration once you have more than one tenant.

First Run

Open the public endpoint in a browser; with no users yet, FusionAuth shows its setup wizard instead of a login page.
1

Create the administrator

Fill in the wizard — it creates the first administrator account — and you are signed into the admin UI as that user.
2

Set the tenant issuer

Under Tenants → Default → General, set Issuer to the HTTPS URL users and applications will use — the canonical endpoint, or your custom domain once configured. It is the iss claim in every token FusionAuth signs, so set it before applications start validating tokens, and configure those applications to expect the same value.
3

Register your application

Under Applications, create one per client and fill in its Authorized redirect URLs, Authorized request origin URLs and Logout URL with your application’s addresses. The generated client Id and client secret go into your application’s OAuth2 configuration.
4

Create an API key

Under Settings → API Keys, create a key for server-side calls to the management API. Store it in a Control Plane secret for the workloads that use it; FusionAuth never writes it anywhere.
5

Add external identity providers (optional)

Under Settings → Identity Providers, configure Google, Microsoft, SAML or other federation. These need outbound access — set firewall.external.outboundAllowCIDR first, or every social login silently does nothing.

Operations

Backing Up

Backups are off by default and are provided by the bundled PostgreSQL template’s backup job. Enable them with postgres.backup.enabled: true, pick a postgres.backup.provider, and complete that provider’s setup first. The job writes postgres-TIMESTAMP.sql.gz objects under the configured prefix in your bucket on every run of postgres.backup.schedule. The dump is a pg_dumpall of the whole server — every FusionAuth tenant, application, user and key.
The backup job is the same one the standalone PostgreSQL template ships. It has not been exercised end to end through this template — rehearse a backup and a restore before relying on it.

AWS S3

  1. Create an S3 bucket. Set postgres.backup.aws.bucket to its name and postgres.backup.aws.region to its region.
  2. If you do not have one yet, create a Control Plane cloud account for the AWS account holding the bucket. Set postgres.backup.aws.cloudAccountName to its name.
  3. Create an IAM policy scoped to exactly that bucket, replacing YOUR_BUCKET_NAME:
  1. Set postgres.backup.aws.policyName to that policy’s name. The template attaches it to the database identity and nothing else — the bucket in your policy is the only storage the backup job can reach.

GCS

  1. Create a GCS bucket. Set postgres.backup.gcp.bucket to its name.
  2. Create a Control Plane cloud account for the GCP project holding the bucket, and set postgres.backup.gcp.cloudAccountName to its name.
  3. Grant the cloud account’s service account the Storage Admin (roles/storage.admin) role. The template additionally binds the identity to roles/storage.objectAdmin on exactly the bucket in postgres.backup.gcp.bucket.

Restoring a Backup

This restore path has not been exercised against this template. It follows from what the chart configures (a pg_dumpall dump, restored with psql) and what the backup image contains, but no restore has been run end to end here. Rehearse it on a throwaway release before you need it.
Each backup is a gzip-compressed pg_dumpall script that recreates the roles and databases it contains, so it is restored by connecting to the postgres maintenance database as the username from your credentials secret. Because the script creates the FusionAuth database rather than merging into it, restore into a server where that database does not exist — a fresh install, or one whose database you have dropped. Run the following from a client that can reach both the bucket and the database. The simplest client is your own machine with a tunnel to the database workload open in another terminal, using --host=127.0.0.1:
1

Stop FusionAuth from holding connections and drop the database

FusionAuth keeps a connection pool open, so drop the database with FORCE (PostgreSQL 13 and later), substituting the database value from your credentials secret:
FusionAuth will log database errors until the restore completes and it is redeployed in the last step.
2

Stream the dump into the server

An already exists error for the role the server created at first boot is expected; the rest of the script loads normally.
3

Redeploy FusionAuth

Force a redeployment so FusionAuth reconnects to the restored database with a clean pool:

Rotating the Database Password

The database reads postgres.credentials.password only when its volume is first initialized, and FusionAuth resolves the secret only when a replica starts. So rotate in three moves: change it inside PostgreSQL, change the value so the chart rewrites the secret, then restart FusionAuth.
1

Change the password inside PostgreSQL

With a tunnel open (cpln port-forward RELEASE_NAME-postgres 5432:5432 --gvc GVC_NAME), connect with the current password and run:
2

Upgrade the release with the new value

Set postgres.credentials.password to the new password in your values and run cpln helm upgrade with your usual arguments. The chart rewrites the credentials secret; nothing else changes.
3

Restart FusionAuth so it picks the new value up

A running replica keeps the password it started with, so force a redeployment:

Upgrading From 2.3.x

The bundled PostgreSQL moved to the postgres 3.4.1 template, which no longer takes database credentials as values. This template absorbed that change rather than passing it on — there is no new prerequisite, only a rename: Carry the same three values across — the existing database was initialized with them and the rename does not change it. A values file that still carries an old key fails the render with the PostgreSQL template’s message telling you to create a dictionary secret yourself. Ignore that advice here: this template creates the secret. Move the three keys and upgrade.

Upgrading From 2.4.0

One thing changed: the default postgres.credentials.password is change-me-fusionauth-db instead of password. The database initialized its data directory with whatever password was in force at first boot, and a new default does not change it, so:
  • If you already set your own password, nothing changes — upgrade normally.
  • If you never overrode it, your database’s password is literally password. Do one of these before upgrading, or FusionAuth fails to authenticate after the upgrade:
1

Keep it working as-is

Set postgres.credentials.password: password explicitly in your values. The upgrade is then a no-op for the database.
2

Or rotate it properly (recommended)

password was a published default, so treat it as compromised. Follow Rotating the Database Password, using the new password as the value you upgrade with.
postgres.credentials.username and postgres.credentials.database are deliberately unchanged for the same reason — they are baked into the initialized data directory, and database also forms the JDBC URL.

Scaling and Availability

  • The FusionAuth tier is a serverless workload that autoscales on request concurrency between one and three replicas; this is fixed in the template, not a value. Running more than one FusionAuth node has not been verified with this template; FusionAuth’s own multi-node guidance expects every node to share the same database and matching configuration, so treat the single-node shape as the supported one.
  • The database is a single instance — there is no high-availability option in this template. A node failure reschedules it onto the same volume: minutes of downtime, no data loss.
  • The first cpln helm upgrade after an install can restart the bundled database, and FusionAuth is unreachable while it comes back. Later upgrades with unchanged values do not.
  • Every upgrade that touches the database restarts it, and FusionAuth with it. Plan upgrades as a short login outage.

Troubleshooting

Symptom: the FusionAuth workload is not ready several minutes after install, and its logs repeat:
Cause: the start script waits for the bundled database by design, for up to five minutes, before launching FusionAuth. On a fresh install the database is still initializing its volume.Fix: usually none — wait for Starting FusionAuth.... If the script instead exits with PostgreSQL did not become ready after 300s. Exiting., the database itself is the problem: check cpln workload get-deployments RELEASE_NAME-postgres --gvc GVC_NAME -o yaml and its logs with cpln logs '{gvc="GVC_NAME", workload="RELEASE_NAME-postgres"}' --limit 50 --since 10m.
Symptom: installing a second FusionAuth release in the same org fails with:
Cause: both releases render the credentials secret under the default name my-fusionauth-db-credentials, and secret names are org-wide. The second install is refused and creates nothing; the first release is untouched.Fix: install the second release with --set postgres.config.credentialsSecretName= set to a name of its own.
Symptom: cpln helm upgrade from 2.3.x stops at render with a message from the PostgreSQL template saying that config.username (or config.password, config.database) was removed and that you should create a dictionary secret.Cause: your values still carry postgres.config.username, postgres.config.password or postgres.config.database, which were renamed in 2.4.0.Fix: do not create a secret — this template creates it. Rename the keys as shown in Upgrading From 2.3.x and upgrade again. The running release is unaffected until the upgrade succeeds.
Symptom: after the upgrade FusionAuth logs database authentication failures and never becomes ready.Cause: the release never overrode postgres.credentials.password, so the database was initialized with the old default password while the new chart wrote change-me-fusionauth-db into the secret.Fix: follow Upgrading From 2.4.0 — either pin the old value explicitly or rotate the password inside PostgreSQL first.
Symptom: clicking a Google, Microsoft or SAML login button returns to the login page or errors, and outbound requests from FusionAuth never arrive at the provider.Cause: firewall.external.outboundAllowCIDR is empty by default, so FusionAuth has no internet egress.Fix: set firewall.external.outboundAllowCIDR to 0.0.0.0/0 or the provider’s address ranges and upgrade. Allow a few minutes for the change to take effect.
Symptom: an application validating FusionAuth tokens reports an iss mismatch, or an OIDC library refuses the discovery document.Cause: the tenant Issuer (Tenants → Default → General) does not match the URL the application was configured to expect — commonly because it was left at its default rather than set to the public endpoint or custom domain.Fix: set the issuer to the HTTPS URL applications use, as in First Run, and make the application’s expected issuer identical. Tokens issued before the change carry the old value.

Important Notes

  • Complete the setup wizard immediately after installing. Inbound is open to 0.0.0.0/0 by default and there is no administrator until the wizard is finished — whoever gets there first creates that account.
  • Change postgres.credentials.password before the first install. It is used exactly as given and applied only when the volume is first initialized; afterwards rotate with ALTER ROLE as in Rotating the Database Password.
  • Give each release its own postgres.config.credentialsSecretName. Secret names are org-wide; a second release left on the default is refused at install.
  • Egress is closed by default. External identity providers, outbound email and internet webhooks need firewall.external.outboundAllowCIDR opened.
  • Set the tenant issuer before applications validate tokens — it is the iss claim in every token, and changing it later invalidates the expectation in every client.
  • cpln helm uninstall deletes the volume set and with it every tenant, application and user. Take a backup first; the volume set keeps only a final snapshot for seven days.
  • Upgrading from 2.3.x or 2.4.0 needs a values change — see Upgrading From 2.3.x and Upgrading From 2.4.0.

External References

FusionAuth Documentation

Official FusionAuth documentation

OAuth2 and OpenID Connect

Authorization code flow, endpoints and token handling

Identity Providers

Federating logins to Google, Microsoft, SAML and other providers

Tenants and the Issuer

Tenant configuration, including the issuer used to sign tokens

FusionAuth Template

View the source files, default values, and chart definition