# Backups (/docs/enterprise/helm/guides/backups)



NetBox Enterprise integrates with [Velero](https://velero.io/) for Kubernetes-native backup and restore. The nbe-operator automatically propagates disaster recovery labels to every managed resource, so Velero can capture the complete deployment state using label selectors.

<Callout type="info">
  Velero backup integration requires an **Enterprise** license tier.
</Callout>

<Callout type="info" title="Embedded Cluster deployments">
  For Embedded Cluster (KOTS) deployments, Velero is pre-installed and backup/restore resources are managed automatically. Use the admin console **Backup** tab instead of the steps below.
</Callout>

## Prerequisites [#prerequisites]

* A running NetBox Enterprise Helm deployment
* Enterprise license
* S3-compatible object storage (AWS S3, MinIO, etc.) for the backup target
* `velero` CLI installed locally ([installation guide](https://velero.io/docs/main/basic-install/))

## Install Velero [#install-velero]

Install Velero with the [node-agent](https://velero.io/docs/main/file-system-backup/) enabled for filesystem-level volume backups. The example below uses the AWS S3 provider - see [Velero supported providers](https://velero.io/docs/main/supported-providers/) for other options.

1. Create a credentials file for your S3 bucket:

```text title="credentials-velero"
[default]
aws_access_key_id=<YOUR_ACCESS_KEY>
aws_secret_access_key=<YOUR_SECRET_KEY>
```

2. Install Velero into the cluster:

```bash
velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.11.1 \
  --bucket <BUCKET_NAME> \
  --secret-file ./credentials-velero \
  --backup-location-config \
    region=<REGION>,s3ForcePathStyle="true",s3Url=<S3_ENDPOINT> \
  --use-node-agent
```

For MinIO or other S3-compatible stores, set `s3Url` to the endpoint (e.g., `https://minio.example.com`). For AWS S3, omit `s3Url` and `s3ForcePathStyle`.

3. Verify Velero is ready:

```bash
velero version
kubectl -n velero get pods
```

## How Label Selection Works [#how-label-selection-works]

The nbe-operator labels every Kubernetes resource it manages. Velero uses these labels with OR semantics to select what to back up:

| Label                                                  | What it covers                                                           |
| ------------------------------------------------------ | ------------------------------------------------------------------------ |
| `app.kubernetes.io/managed-by: netbox-operator`        | Operator-managed resources (deployments, services, PVCs, jobs)           |
| `netboxlabs.com/managed-by: netbox-operator`           | Sub-operator CRs, chart template resources (Redis, PGO, gateway/ingress) |
| `app.kubernetes.io/part-of: netbox-enterprise`         | Helm subchart resources whose charts hardcode `managed-by: Helm`         |
| `postgres-operator.crunchydata.com/control-plane: pgo` | CrunchyData PGO operator control plane                                   |

Pods with persistent volumes are annotated with `backup.velero.io/backup-volumes` so Velero knows which volumes to capture via filesystem backup.

## Create Backup Resources [#create-backup-resources]

Apply the following resources to your cluster. Replace `netbox` with your namespace if different.

### Volume policy filter [#volume-policy-filter]

This ConfigMap tells Velero to skip ephemeral volume types that contain no persistent data:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: netbox-enterprise-backup-resource-filters
  namespace: velero
  labels:
    velero.io/resource-filter-policies: "true"
data:
  backup-resource-filters.yaml: |
    version: v1
    volumePolicies:
      - conditions:
          volumeTypes:
            - emptyDir
            - configmap
        action:
          type: skip
```

## Create a Backup [#create-a-backup]

### On-demand backup [#on-demand-backup]

```bash
velero backup create netbox-backup \
  --or-selector "app.kubernetes.io/managed-by=netbox-operator or netboxlabs.com/managed-by=netbox-operator or app.kubernetes.io/part-of=netbox-enterprise or postgres-operator.crunchydata.com/control-plane=pgo" \
  --include-namespaces netbox,velero \
  --include-cluster-resources=true \
  --default-volumes-to-fs-backup \
  --wait
```

If you set up a schedule (below), you can also trigger an immediate backup from it:

```bash
velero backup create --from-schedule netbox-enterprise-daily --wait
```

### Scheduled backup [#scheduled-backup]

Create a `Schedule` to run backups automatically. This example runs daily at 02:00 UTC with 30-day retention:

```yaml
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: netbox-enterprise-daily
  namespace: velero
spec:
  schedule: "0 2 * * *"
  template:
    includeClusterResources: true
    includedNamespaces:
      - netbox
      - velero
    defaultVolumesToFsBackup: true
    ttl: 720h
    resourcePolicy:
      kind: ConfigMap
      name: netbox-enterprise-backup-resource-filters
    orLabelSelectors:
      - matchLabels:
          app.kubernetes.io/managed-by: netbox-operator
      - matchLabels:
          netboxlabs.com/managed-by: netbox-operator
      - matchLabels:
          app.kubernetes.io/part-of: netbox-enterprise
      - matchLabels:
          postgres-operator.crunchydata.com/control-plane: pgo
```

### Check backup status [#check-backup-status]

```bash
velero backup get
velero backup describe netbox-backup --details
velero backup logs netbox-backup
```

## Restore from Backup [#restore-from-backup]

1. **Enable maintenance mode** to stop the application:

```bash
kubectl -n netbox patch netboxenterprise netbox \
  --type merge \
  -p '{"spec":{"maintenanceMode":true}}'
```

2. **Restore the backup**:

```bash
velero restore create --from-backup netbox-backup --wait
```

3. **Check restore status**:

```bash
velero restore describe netbox-backup --details
```

4. **Disable maintenance mode** to resume:

```bash
kubectl -n netbox patch netboxenterprise netbox \
  --type merge \
  -p '{"spec":{"maintenanceMode":false}}'
```

## Data Preservation [#data-preservation]

When a `NetBoxEnterprise` resource is deleted, PersistentVolumeClaims are **preserved** (not deleted) to prevent accidental data loss. This allows re-creating the cluster and reattaching existing data volumes.

## Next Steps [#next-steps]

* [Maintenance Mode](/enterprise/helm/guides/maintenance-mode/) - Take NetBox offline during restore
* [Security](/enterprise/helm/guides/security/) - Protect backup credentials
* [Velero documentation](https://velero.io/docs/main/) - Full Velero reference
