Skip to main content

Overview

PostGIS extends PostgreSQL with geographic object types, spatial indexes and spatial SQL functions, making it the standard choice for location-aware applications. This template deploys one PostgreSQL 18 server with PostGIS 3.6 on a persistent volume, and an optional cron job that writes compressed pg_dumpall backups to AWS S3 or Google Cloud Storage. Database credentials are not template values. The server reads its username, password and database name from a dictionary secret you create before installing, so no password passes through Helm or lands in the release. The template creates no credential secret of its own.
This template deploys into an existing GVC that you already have. It does not create or manage a GVC.
This is a single server, not a cluster — there is no replication or failover. There is no PostGIS variant of the clustered PostgreSQL templates; if you need both spatial support and automatic failover, start from PostgreSQL Highly Available and install the extension yourself.

What Gets Created

Prerequisites

One secret must exist before you install. It holds the credentials your applications put in their connection strings. Secrets are org-level, so no GVC flag is involved.
1

Create the database credentials secret

A dictionary secret holding exactly three keys — username, password and database. The first time the volume is initialized, the server creates that user (as a superuser) and that database, and loads the PostGIS extensions into it:
Set config.credentialsSecretName to this name. Read it back later with cpln secret reveal SECRET_NAME -o yaml — a bare cpln secret reveal prints only a summary table, not the values.
Create the secret before installing, or the deployment wedges silently. A config.credentialsSecretName that points at a secret which does not exist installs successfully and then never starts. The container never runs, so cpln logs returns zero lines. The one place the reason appears is status.versions[].message:
Use get-deployments — plain cpln workload get has no versions key. Creating the missing secret repairs the deployment on its own within several minutes, or run cpln workload force-redeployment RELEASE_NAME-postgis --gvc GVC_NAME to skip the wait.
Backups are optional and need a bucket plus a Control Plane cloud account — see Backing Up. Nothing else is required for a default install.

Installation

Install the chart from the marketplace registry, pointing it at the secret you created:
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.

Server and Resources

On a stateful workload the ratio of maxCpu to minCpu may not exceed 4:1. Raising maxCpu without raising minCpu can cross that limit and is rejected when the workload is applied.

Credentials

The three keys are applied only when the volume is first initialized. Changing the secret afterwards does not change the stored password — see Rotating the Password.

Storage

Internal Access

This template has no public access knob; the server is reachable only from inside Control Plane. A change to internalAccess can take several minutes to take effect — re-test before concluding it did not apply.

Backup

A cron workload runs pg_dumpall on the schedule and uploads a gzip-compressed SQL dump of every database and role to the bucket for the chosen provider. It authenticates with the username and password from your credentials secret. Each provider’s bucket, cloud account and policy steps are under Backing Up.
Backups require PostgreSQL 17 or later, and backup.image must match the server’s major version: tag 18.1.0 for postgis/postgis:18-*, 17.1.0 for postgis/postgis:17-*. A mismatched client refuses to dump a newer server.

Connecting

This template exposes no public endpoint. Everything below is reachable from inside the GVC, subject to internalAccess.type. The database named in your secret has the postgis and postgis_topology extensions (plus fuzzystrmatch and postgis_tiger_geocoder on PostGIS 3.6) loaded at first boot. The image also creates a template_postgis template database with the same extensions, so CREATE DATABASE newdb TEMPLATE template_postgis; gives any additional database spatial support without running CREATE EXTENSION yourself. To verify from your own machine, tunnel to the server and connect with psql:
Or run psql inside the container, where local connections need no password:

Operations

Backing Up

Backups are off by default. Enable them with backup.enabled: true, pick a backup.provider, and complete that provider’s setup below first. The job writes postgres-TIMESTAMP.sql.gz objects under backup.PROVIDER.prefix in your bucket on every run of backup.schedule.
The backup and restore procedures on this page follow the chart’s configuration and the published backup image, which are shared with the PostgreSQL template, but they have not been exercised end to end on a PostGIS install. Rehearse a backup and a restore before relying on them.

AWS S3

  1. Create an S3 bucket. Set backup.aws.bucket to its name and 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 backup.aws.cloudAccountName to its name.
  3. Create an IAM policy scoped to exactly that bucket, replacing YOUR_BUCKET_NAME:
  1. Set backup.aws.policyName to that policy’s name. The template attaches it to the workload 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 backup.gcp.bucket to its name.
  2. Create a Control Plane cloud account for the GCP project holding the bucket, and set 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 backup.gcp.bucket.

On-Demand Dump

Without scheduled backups, or before a risky change, take a single-database dump with pg_dump inside the container. Binary output must be wrapped in base64 on both sides — cpln workload exec corrupts raw binary streams:
Check the file before trusting it — pg_restore -l DATABASE.dump lists its contents and fails on a corrupted archive.

Restoring a Backup

Each scheduled backup is a gzip-compressed pg_dumpall script, so it is restored by connecting to the postgres maintenance database as the superuser from your credentials secret; the script recreates the roles and databases it contains, including the CREATE EXTENSION statements for PostGIS. Run the commands from a client that can reach both the bucket and the server — a workload inside the GVC, or your own machine with cpln port-forward RELEASE_NAME-postgis 5432:5432 --gvc GVC_NAME open and --host=127.0.0.1 in place of the internal hostname.
already exists errors for the role, the database and the template_postgis template that the server created at first boot are expected; the rest of the script loads normally. Restore into an empty server (a fresh install, or one whose databases you have dropped) to avoid duplicate-object errors on existing tables. To restore an on-demand dump, send it back through cpln workload exec with --stdin — stdin is off by default and a file piped in without it is silently discarded. Restore into an empty database; CREATE DATABASE DATABASE TEMPLATE template_postgis; gives you one with the extensions already loaded:

Rotating the Password

The server reads the secret only when the volume is first initialized, so change the password inside PostgreSQL first, then update the secret to match:
Workloads resolve the secret when a replica starts, so an updated secret is not picked up by a running replica. The server does not need one — it keeps serving with the password now stored in the database — and the backup job reads the secret fresh on its next scheduled run.

Upgrading From 1.3.2 or Earlier

Template versions up to 1.3.2 took the database credentials as plain Helm values with a working default password, and wrote them into a chart-owned secret named after the release. Version 1.4.0 removed both, and an upgrade that still carries the old keys is refused at render — your existing release is left running rather than restarted against a different password.
1

Read the credentials the database already uses

An existing database keeps the credentials it was initialized with. Recover them from your current values file, or from the secret the old version created — before upgrading:
2

Create the prerequisite secret with those same values

Follow Prerequisites using the existing username, password and database. Different values here do not change the database — they only leave the workload unable to authenticate.
3

Remove the old keys from your values

Delete config.username, config.password and config.database, and set config.credentialsSecretName to your secret’s name. If you set resources.cpu or resources.memory, rename them to resources.maxCpu and resources.maxMemory.
4

Upgrade, then rotate any default password

After the upgrade succeeds, change any password that came from a 1.3.x default — those defaults were published in the public template repository, so treat them as compromised. Follow Rotating the Password.
RELEASE_NAME-postgis-config no longer holds credentials. Anything outside this release that read the username or password from it by name — another workload’s environment, a policy, or a parent chart that bundles PostGIS as a subchart — must be pointed at the secret you created instead. A reference to a key that no longer exists does not fail loudly; it wedges the referring workload silently, exactly as described in Prerequisites.

Upgrading From 1.4.0

Version 1.4.1 removes the aws::ReadOnlyAccess managed policy from the backup identity. That policy granted read access to every bucket in your AWS account and contained no write actions, so it never carried the backup itself — but it was silently supplying any read action your own bucket-scoped policy happened to omit. The identity now carries cpln-connector and your backup.aws.policyName policy only. Before upgrading an AWS-backed release, check that your IAM policy contains the full action list under AWS S3. If it already matches, no action is needed. GCS-backed releases and releases without backups are unaffected.

Scaling and Availability

  • The server is pinned to one replica. Do not raise it — a single volume set backs a single server, and a second replica cannot mount it. A second replica would be an isolated instance, not a member of a cluster.
  • Every cpln helm upgrade restarts the server, including the first upgrade after an install even when nothing changed. Plan each one as a short write outage.
  • A node failure reschedules the server and reattaches the same volume. The exposure is minutes of downtime, not data loss.

Troubleshooting

Symptom: the install succeeds, the workload stays not ready indefinitely, and cpln logs '{gvc="GVC_NAME", workload="RELEASE_NAME-postgis"}' --limit 50 --since 10m returns zero lines.Cause: config.credentialsSecretName names a secret that does not exist, so the container is never started. The message is only visible in status.versions[].message:
Fix: create the secret as in Prerequisites. The deployment recovers on its own within several minutes, or run cpln workload force-redeployment RELEASE_NAME-postgis --gvc GVC_NAME.
Symptom: cpln helm upgrade stops before touching any resource:
Cause: your values still carry keys that were removed in 1.4.0.Fix: follow Upgrading From 1.3.2 or Earlier. Your running release is unaffected until the upgrade succeeds.
Symptom: you updated the password key in the credentials secret, but the server still accepts the previous password and rejects the new one.Cause: the secret is applied only when the volume is first initialized. Afterwards the stored password lives in the database, not the secret.Fix: change it inside PostgreSQL and then update the secret to match — see Rotating the Password.
Symptom: cpln logs '{gvc="GVC_NAME", workload="RELEASE_NAME-postgis-backup"}' --limit 50 --since 1d shows the run ending in aborting because of server version mismatch, and no new object appears in the bucket.Cause: backup.image carries an older PostgreSQL major than image. pg_dumpall refuses to dump a server newer than itself.Fix: set backup.image to the tag matching your server — 18.1.0 for a PostgreSQL 18 image, 17.1.0 for 17 — and upgrade the release.
Symptom: an install or upgrade fails and the server workload is not created or updated.Cause: resources.maxCpu is more than four times resources.minCpu, which the platform rejects on a stateful workload.Fix: raise resources.minCpu or lower resources.maxCpu so the ratio is at most 4:1.

Important Notes

  • Create the credentials secret before installing. A reference to a secret that does not exist wedges the workload with no log output; see Prerequisites for the one command that shows the reason.
  • Credentials are read only when the volume is first initialized. Rotate with ALTER ROLE inside PostgreSQL, then update the secret — see Rotating the Password.
  • Do not scale the server past one replica. It is a single instance on a single volume, not a replicated cluster.
  • cpln helm uninstall deletes the volume set and the database with it; a final snapshot is kept for 7 days. Your credentials secret is yours and is left alone.
  • Every cpln helm upgrade restarts the server. Treat each one as a short planned write outage.
  • Match backup.image to the server’s major version (18.1.0 for PostgreSQL 18, 17.1.0 for 17), or the backup job fails on every run.
  • Upgrading from 1.3.2 or earlier is a breaking change — the removed keys stop the upgrade rather than resetting a password. See Upgrading From 1.3.2 or Earlier.

External References

PostGIS Documentation

Official PostGIS manuals and tutorials

PostGIS Docker Image

Source of the server image, including the first-boot extension and template_postgis setup

PostgreSQL Backup and Restore

Upstream guidance on pg_dumpall dumps and restores

Backup Image Source

Source for the PostgreSQL backup container image

PostGIS Template

Source files, default values, and chart definition