Custom Plugins
NetBox Enterprise ships with built-in plugins, but you can add your own by packaging them into a wheelhouse archive and configuring the operator to install them at pod startup.
How it works
A wheelhouse is a .tar.gz containing a wheelhouse/ directory with .whl files, a requirements.txt, and a constraints.txt. On each pod start, the entrypoint extracts the archive and runs pip install --target to install the packages before Django loads.
The operator supports three wheelhouse sources:
| Media directory | PVC | S3 | |
|---|---|---|---|
| Best for | Quick setup, single-node, 1.x upgrades | Dev/test, single-node | Production, multi-node |
| CRD wheelhouse config | Not required | Required | Required |
| Upload method | kubectl cp to running pod | kubectl cp during maintenance mode | S3 CLI |
| Updates | Copy new file, restart pods | Maintenance mode → copy → resume | Upload to S3, restart pods |
Build the wheelhouse
Follow the wheelhouse build instructions in the Embedded Cluster custom plugins guide. The build process is identical — you end up with a wheelhouse.tar.gz containing your plugin wheels, requirements.txt, and constraints.txt.
The short version:
- Extract
constraints.txtfrom a running NetBox pod - Create
requirements.txtwith your plugins pinned to exact versions pip downloadthe wheels for the correct platform (x86_64oraarch64)tar czf wheelhouse.tar.gz -C /tmp wheelhouse/
Install via media directory (simplest)
The media directory method requires no CRD wheelhouse configuration. Copy the wheelhouse tarball directly to a running pod's media directory, configure customPythonConfig, and restart.
1. Find a NetBox pod
NETBOX_POD=$(kubectl get pods -n netbox \
-l netboxlabs.com/custom-plugins-upload=true \
-o jsonpath='{.items[0].metadata.name}')
2. Copy the wheelhouse
kubectl cp /tmp/wheelhouse.tar.gz \
netbox/$NETBOX_POD:/opt/netbox/netbox/media/wheelhouse.tar.gz
3. Configure plugins in your values file
Add customPythonConfig — no wheelhouse section is needed:
netboxEnterprise:
spec:
netbox:
config:
customPythonConfig: |
PLUGINS = ['my_plugin']
PLUGINS_CONFIG = {
'my_plugin': {
'setting': 'value',
},
}
4. Apply and restart
helm upgrade netbox-enterprise oci://registry.replicated.com/netbox-enterprise/nbe-operator \
--values values.yaml -n netbox
kubectl rollout restart deployment -n netbox netbox-netbox
kubectl rollout restart deployment -n netbox netbox-netbox-worker
This method works best with a single replica. If your deployment uses multiple replicas with a shared media volume, the file is available to all pods. For deployments without shared media, use the S3 method instead.
Install via S3 (production)
1. Create an S3 credentials secret
kubectl -n netbox create secret generic wheelhouse-s3-creds \
--from-literal=AWS_ACCESS_KEY_ID=<YOUR_KEY> \
--from-literal=AWS_SECRET_ACCESS_KEY=<YOUR_SECRET>
2. Upload the wheelhouse
aws s3 cp /tmp/wheelhouse.tar.gz s3://my-bucket/media/wheelhouse.tar.gz
For S3-compatible stores (MinIO, DigitalOcean Spaces, etc.):
aws s3 cp /tmp/wheelhouse.tar.gz \
s3://my-bucket/media/wheelhouse.tar.gz \
--endpoint-url=https://s3.example.com
3. Configure the CRD
Add the wheelhouse source and plugin config to your values file:
netboxEnterprise:
spec:
netbox:
config:
plugins:
wheelhouse:
s3:
bucket: my-bucket
key: media/wheelhouse.tar.gz # default
region: us-east-1
endpoint: https://s3.example.com # omit for AWS S3
credentialsSecret:
name: wheelhouse-s3-creds
accessKeyId: AWS_ACCESS_KEY_ID # key name in the secret
secretAccessKey: AWS_SECRET_ACCESS_KEY
verifySSL: true # default
customPythonConfig: |
PLUGINS = ['my_plugin']
PLUGINS_CONFIG = {
'my_plugin': {
'setting': 'value',
},
}
Apply with helm upgrade, or patch the CR directly:
helm upgrade netbox-enterprise oci://registry.replicated.com/netbox-enterprise/nbe-operator \
--values values.yaml -n netbox
4. Restart pods
After uploading a new wheelhouse, restart both the web and worker deployments:
kubectl rollout restart deployment -n netbox netbox-netbox
kubectl rollout restart deployment -n netbox netbox-netbox-worker
S3 field reference
| Field | Type | Default | Description |
|---|---|---|---|
s3.bucket | string | Required | S3 bucket name |
s3.key | string | media/wheelhouse.tar.gz | Object key in the bucket |
s3.region | string | us-east-1 | AWS region |
s3.endpoint | string | — | S3-compatible endpoint URL (omit for AWS) |
s3.credentialsSecret.name | string | Required | Secret name |
s3.credentialsSecret.accessKeyId | string | AWS_ACCESS_KEY_ID | Key within the secret for access key |
s3.credentialsSecret.secretAccessKey | string | AWS_SECRET_ACCESS_KEY | Key within the secret for secret key |
s3.verifySSL | bool | true | Verify SSL certificates |
Install via PVC (dev/test)
The PVC method stores the wheelhouse on a persistent volume. You upload the tarball during maintenance mode, when the operator creates a pod with the PVC mounted read-write.
1. Configure the CRD and enable maintenance mode
netboxEnterprise:
spec:
maintenanceMode: true
netbox:
config:
plugins:
wheelhouse:
pvc:
claimName: netbox-wheelhouse
path: wheelhouse.tar.gz # default
create: true # operator creates the PVC
size: 1Gi # default
customPythonConfig: |
PLUGINS = ['my_plugin']
PLUGINS_CONFIG = {
'my_plugin': {
'setting': 'value',
},
}
2. Wait for the maintenance pod and copy the wheelhouse
kubectl wait --for=condition=Ready pod \
-n netbox -l maintenance-mode=true --timeout=120s
MAINT_POD=$(kubectl get pod -n netbox \
-l maintenance-mode=true \
-o jsonpath='{.items[0].metadata.name}')
kubectl cp /tmp/wheelhouse.tar.gz \
netbox/$MAINT_POD:/wheelhouse-source/wheelhouse.tar.gz
3. Disable maintenance mode
kubectl -n netbox patch netboxenterprise netbox \
--type merge -p '{"spec":{"maintenanceMode":false}}'
The operator starts NetBox normally. The entrypoint extracts and installs the wheelhouse, then Django loads your plugins.
PVC field reference
| Field | Type | Default | Description |
|---|---|---|---|
pvc.claimName | string | Required | PVC name |
pvc.path | string | wheelhouse.tar.gz | Path to the tarball within the PVC |
pvc.create | bool | false | Let the operator create and manage the PVC |
pvc.size | string | 1Gi | PVC size (only when create: true) |
pvc.storageClassName | string | — | Storage class (only when create: true) |
Enabling plugins
Plugins are enabled via customPythonConfig (shown in the examples above). The config is mounted as zzz_80_user_extra.py — the operator's own plugin loader imports your PLUGINS list, filters out managed plugins (branching, changes, diode, etc.), then appends the built-in enterprise plugins after yours.
customPythonConfig: |
PLUGINS = ['my_plugin', 'another_plugin']
PLUGINS_CONFIG = {
'my_plugin': {
'option_a': True,
},
'another_plugin': {
'api_key': 'abc123',
},
}
For plugin-specific settings, see each plugin's documentation and the NetBox plugin configuration reference.
Verification
After pods restart, confirm plugins loaded:
# check entrypoint logs for wheelhouse installation
kubectl logs -n netbox deploy/netbox-netbox | grep -E 'wheelhouse|plugin'
# verify plugins are in the Django config
kubectl exec -n netbox deploy/netbox-netbox -- \
python3 -c "from netbox.configuration import PLUGINS; print(PLUGINS)"
You can also log in to NetBox and navigate to /plugins/ to see installed plugins.
Updating plugins
Media directory: copy the new wheelhouse.tar.gz to the pod's media directory, then restart both deployments.
S3: upload the new wheelhouse.tar.gz to the same S3 key, then restart both deployments.
PVC: enable maintenance mode, copy the new tarball to the maintenance pod, disable maintenance mode.
When upgrading NetBox Enterprise to a version with a different NetBox release, rebuild the wheelhouse with the new constraints.txt — see upgrade instructions.
Troubleshooting
See the custom plugins troubleshooting section for common issues with wheelhouse builds, S3 downloads, and plugin loading.
Next Steps
- Built-in Plugins — Plugins included in every release
- Maintenance Mode — Required for PVC uploads
- NetBox Configuration — Other
customPythonConfigoptions