PostgreSQL Configuration
Configure internal PGO-managed or external PostgreSQL for NetBox Enterprise
NetBox Enterprise supports two PostgreSQL deployment modes:
- Internal (default): Managed by the Crunchy Postgres Operator (PGO), installed as a chart dependency
- External: Connect to an existing PostgreSQL instance you manage
Internal PostgreSQL (Default)
When postgresql.external: false (the default), the operator deploys a PostgresCluster resource that PGO manages.
| Key | Type | Default | Description |
|---|---|---|---|
postgresql.external | bool | false | Use internal PostgreSQL |
postgresql.instances | uint8 | 0 | Number of PostgreSQL replicas. 0 auto-scales to min(nodes, 3) (0-255) |
postgresql.version | string | 18 | PostgreSQL major version |
postgresql.storageSize | string | 4Gi | Storage size for each PostgreSQL instance |
postgresql.storageClassName | string | - | Storage class (uses cluster default if not set) |
postgresql.registry | string | - | Container registry override for PGO images |
postgresql.resources.cpu | int | - | CPU request in millicores (optional) |
postgresql.resources.memory | int | - | Memory request in MiB (optional) |
postgresql.limits.cpu | int | - | CPU limit in millicores (optional) |
postgresql.limits.memory | int | - | Memory limit in MiB (optional) |
postgresql.backups | object | see Backups | pgBackRest backup settings |
When resources or limits are not set, no resource requests or limits are applied to PostgreSQL pods, allowing PGO to use Kubernetes defaults. Set limits to prevent PostgreSQL from consuming excessive node resources.
Example with redundancy and resource limits:
netboxEnterprise:
spec:
postgresql:
external: false
instances: 2
version: "18"
storageSize: "20Gi"
resources:
cpu: 500
memory: 1024
limits:
cpu: 2000
memory: 2048PGO automatically handles:
- Database creation (
netbox,diode,hydradatabases) - User management and credential rotation
- Replication between primary and replica instances
- Failover and recovery
The operator detects PGO password rotations automatically using resourceVersion-based change detection and triggers rolling updates without reading sensitive secret data.
Backups
New in 2.3.0. The internal database is backed up by pgBackRest, which PGO runs on the operator's behalf. It is on by default, so on a supported storage class a default install has working disaster recovery with no configuration.
Two facts decide whether a restore returns your database
- Your storage class must not provision
hostPathPersistentVolumes. Velero skips them without an error, so the backup reportsCompletedholding no volume data.local-path-provisioner— the default in k3s, k3d, and kind — provisionshostPathvolumes and gives you no working disaster recovery at all. - A completed Velero restore always leaves the PostgreSQL data volume empty. It is excluded from the backup on purpose. The database is rebuilt from the pgBackRest repository, which is a separate step.
See Storage requirements and Restore procedure.
netboxEnterprise:
spec:
postgresql:
backups:
enabled: true
repoStorageSize: 16Gi
retentionFull: 4
fullSchedule: "0 1 * * 0"
incrementalSchedule: "0 1 * * 1-6"| Key | Type | Default | Description |
|---|---|---|---|
postgresql.backups.enabled | bool | true | Whether pgBackRest runs |
postgresql.backups.repoStorageSize | string | 16Gi | Size of the pgBackRest repository PVC |
postgresql.backups.repoStorageClassName | string | - | Storage class for the repository PVC. Falls back to the PostgreSQL data storage class, then to the cluster default. It must not be a hostPath class: the repository is the only copy of your database in the Velero archive, and Velero cannot read a hostPath volume. |
postgresql.backups.retentionFull | int | 4 | Number of full backup sets to keep |
postgresql.backups.fullSchedule | string | 0 1 * * 0 | Cron schedule for full backups. An empty string disables them. |
postgresql.backups.incrementalSchedule | string | 0 1 * * 1-6 | Cron schedule for incremental backups. An empty string disables them. |
The repository PVC is separate from the PostgreSQL data PVC, and it is larger by default. It holds a full backup set plus the write-ahead log archived since that set.
The whole section is ignored when postgresql.external is true. An external database has no operator-managed repository.
enabled: false leaves the database backed up by nothing
Velero's filesystem backup excludes the PostgreSQL data volume, and that exclusion stays in place when pgBackRest is off. A file-by-file copy of a live data directory is a torn copy, and one that looks restorable is worse than none. So this setting is an opt-out from PostgreSQL disaster recovery, not a choice of a different mechanism.
Disabling it on a running cluster also pauses PGO's reconciliation of the cluster, which the operator reports as PostgresReconciliationPaused=True.
See PostgreSQL Backups and Disaster Recovery for verification commands and the restore procedure.
External PostgreSQL
Set postgresql.external: true to use an externally managed PostgreSQL instance.
netboxEnterprise:
spec:
postgresql:
external: trueWhen using an external database, you must provide connection details through netbox.config.postgres:
netboxEnterprise:
spec:
netbox:
config:
postgres:
database: "netbox"
user: "netbox"
password:
name: netbox-db-credentials
key: passwordHost and port are configured via postgresqlProfiles (see below).
You can disable PGO entirely when using an external database:
pgo:
enabled: falseSee the External Database Guide for a complete step-by-step walkthrough.
PostgreSQL Profiles
When multiple components (NetBox, Diode, Hydra) connect to the same PostgreSQL server, define a named profile in postgresqlProfiles so connection details and TLS settings are specified once:
netboxEnterprise:
spec:
postgresqlProfiles:
netbox:
host: "postgres.example.com"
port: 5432
tlsConfig:
sslmode: verify-full
keychainCaCertificates:
- postgres-ca
postgresql:
external: true
postgresqlProfile: netbox
diode:
config:
reconciler:
postgres:
postgresqlProfile: netbox
password:
name: diode-db-credentials
key: password
hydra:
postgresqlProfile: netboxEach component references the profile by name and provides only its own password secret. See the NetBoxEnterprise CRD for the full profile field reference.
TLS Configuration
TLS for PostgreSQL connections is configured through postgresqlProfiles:
| Key | Type | Default | Description |
|---|---|---|---|
postgresqlProfiles.<name>.tlsConfig.sslmode | enum | prefer | SSL mode for connections |
postgresqlProfiles.<name>.tlsConfig.insecureSkipVerify | bool | false | Skip TLS verification (dev only) |
postgresqlProfiles.<name>.tlsConfig.keychainCaCertificates | list | - | CA certificate names from tlsKeychain |
postgresqlProfiles.<name>.tlsConfig.keychainClientCertificate | string | - | Client certificate name from tlsKeychain |
SSL Modes
| Mode | Description |
|---|---|
disable | No SSL |
allow | Try non-SSL first, then SSL |
prefer | Try SSL first, then non-SSL (default) |
require | SSL required, no certificate verification |
verify-ca | SSL required, verify server CA |
verify-full | SSL required, verify CA and hostname |
When CA certificates are configured via keychainCaCertificates, libpq verifies the server certificate even with sslmode: require (effectively upgrading it to verify-ca behavior). This is because the operator sets PGSSLROOTCERT when CA certificates are provided. Ensure the CA certificate matches the server, or omit it to use require without verification.
TLS with CA Verification
netboxEnterprise:
spec:
postgresqlProfiles:
netbox:
host: "postgres.example.com"
port: 5432
tlsConfig:
sslmode: verify-ca
keychainCaCertificates:
- my-postgres-ca
postgresql:
external: true
postgresqlProfile: netbox
tlsKeychain:
caCertificateSecrets:
- name: my-postgres-ca
secret: postgres-ca-secret
key: ca.crtTLS with Client Certificates (mTLS)
netboxEnterprise:
spec:
postgresqlProfiles:
netbox:
host: "postgres.example.com"
port: 5432
tlsConfig:
sslmode: verify-full
keychainCaCertificates:
- my-postgres-ca
keychainClientCertificate: my-client-cert
postgresql:
external: true
postgresqlProfile: netbox
tlsKeychain:
caCertificateSecrets:
- name: my-postgres-ca
secret: postgres-ca-secret
key: ca.crt
clientCertificateSecrets:
- name: my-client-cert
secret: postgres-client-cert
certKey: tls.crt
privateKey: tls.keyDatabase Users
When using internal PostgreSQL, PGO creates the following database users by default:
| User | Database | Purpose |
|---|---|---|
netbox | netbox | NetBox application |
diode | diode | Diode reconciler (if Diode enabled) |
hydra | hydra | Hydra OIDC server (if Diode enabled) |
Next Steps
- External Database Guide - Full walkthrough
- Redis - Cache and queue configuration
- Security - TLS best practices