Configuration¶
Plugin registration¶
Add netbox_packer to your PLUGINS list and configure it in
PLUGINS_CONFIG inside netbox/configuration.py:
PLUGINS = [
# ... other plugins
"netbox_packer",
]
PLUGINS_CONFIG = {
"netbox_packer": {
# No required keys at startup.
# Runtime settings are managed via PackerPluginSettings in the UI.
},
}
PackerPluginSettings¶
After running migrations, the singleton settings row exists in the database
(PackerPluginSettings.get_solo()), but there is currently no NetBox UI page
and no REST API endpoint for it — there is no navigation menu entry, no
registered model view, and the plugin's API router only registers
packer-templates, build-jobs, installer-configs, and build-targets (not
plugin-settings). The only supported way to read or write these fields today
is the Django/NetBox Python shell (manage.py nbshell or manage.py shell);
see "Storing the key" below.
| Setting | Model field | Description |
|---|---|---|
| Proxbox API URL | proxbox_api_url |
Base URL of the proxbox-api backend (e.g. http://10.0.30.207:8000). Required for cloud_config installer-type builds. |
| Proxbox API key | proxbox_api_key_encrypted |
Set only via set_proxbox_api_key() / read via get_proxbox_api_key() — never stored or read as plaintext. See key management below. |
| File Server package-read user | fileserver_package_read_user |
Plaintext username for the dedicated non-human Gitea package reader. |
| File Server package-read token | fileserver_package_read_token_encrypted |
Set only via set_fileserver_package_read_token() / read via get_fileserver_package_read_token() — never stored or read as plaintext. |
| Enable branching | branching_enabled |
When True, staleness-check jobs run inside a netbox-branching branch. |
| Branch name prefix | branch_name_prefix |
Prefix for auto-created branch names (default: packer-stale). |
| Branch conflict behavior | branch_on_conflict |
fail (leave branch open) or acknowledge (merge anyway). |
Proxbox API key management¶
The proxbox-api key is not stored in plain text. It is encrypted with a
Fernet cipher derived from settings.SECRET_KEY (SHA-256 → base64url). There
is no dependency on netbox-nms for this encryption.
Storing the key¶
Via the Python shell. This is currently the only supported way to set or
rotate the key (there is no UI form or REST endpoint for PackerPluginSettings
yet):
from netbox_packer.models import PackerPluginSettings
settings_row = PackerPluginSettings.get_solo()
settings_row.set_proxbox_api_key("your-proxbox-api-key-here")
settings_row.save()
proxbox_api_url can be set the same way (settings_row.proxbox_api_url = "...")
before calling .save().
Verifying the key¶
from netbox_packer.models import PackerPluginSettings
settings_row = PackerPluginSettings.get_solo()
key = settings_row.get_proxbox_api_key()
print("Key configured:", bool(key))
File Server package-index credential management¶
The File Server golden-image bake reads its package-index credential from the
same singleton settings row, not from the NetBox or RQ service environment.
The username is not secret; the token uses the same Django SECRET_KEY-derived
Fernet cipher as the proxbox-api key. Set it from the Django/NetBox shell:
from netbox_packer.models import PackerPluginSettings
settings_row = PackerPluginSettings.get_solo()
settings_row.fileserver_package_read_user = "nms-pkg-reader"
settings_row.set_fileserver_package_read_token("<gitea-package-read-token>")
settings_row.save()
Use a dedicated non-human Gitea identity and grant package-Read permission only.
Never use a personal token or PACKAGE_WRITE_TOKEN. When the token changes,
rotate it through the setter and rebake File Server VMID 9300; existing images
and clones retain the credential already baked into root-only
/etc/nms-fileserver-agent/pip.conf.
proxbox-api prerequisites¶
The cloud_config bake path requires:
proxbox-api >= 0.0.19.post5— netbox-packer requires the signed preflight contract: a non-executing build plan returnsrecipe_digest,/cloud/templates/images/preflightreturns an expiringplan_token, and the execute request consumes that token. A 404 from the preflight endpoint is an incompatible older service and fails closed; there is no legacy one-step fallback. The runtime image includesopenssh-clientstarting from0.0.18.post1.PROXBOX_ENABLE_CLOUD_IMAGE_EXECUTION=true— set in the proxbox-api environment. Cloud image execution is disabled by default.PROXBOX_SSH_KEY_DIR— directory on the proxbox-api host containing the SSH private key that trusts the target Proxmox host.allow_writes=Trueon the targetProxmoxEndpointrow in netbox-proxbox.- The selected Proxmox storage pool must have the
snippets,import, andimagescontent types enabled.
For detailed host bootstrap steps (key provisioning, storage content types), see
the nmulticloud-context deploy documentation at
deploy/docs/proxbox-api-cloud-image-bake.md.
Environment variables (proxbox-api side)¶
These are set on the proxbox-api service, not on the NetBox host:
| Variable | Required | Description |
|---|---|---|
PROXBOX_ENABLE_CLOUD_IMAGE_EXECUTION |
Yes | Set to true to enable bake jobs |
PROXBOX_SSH_KEY_DIR |
Yes | Directory containing SSH private key(s) for Proxmox hosts |
PROXBOX_NETBOX_TIMEOUT |
No | Timeout for NetBox API calls, default 120s |
PROXBOX_ENCRYPTION_KEY |
Yes | Fernet key for proxbox-api credential storage |
Validation¶
After saving PackerPluginSettings, verify from the NetBox shell:
from netbox_packer.models import PackerPluginSettings
import urllib.request
s = PackerPluginSettings.get_solo()
print("URL:", s.proxbox_api_url)
print("Key set:", bool(s.get_proxbox_api_key()))
# Quick connectivity check
req = urllib.request.Request(
s.proxbox_api_url.rstrip("/") + "/status",
headers={"X-Proxbox-API-Key": s.get_proxbox_api_key()},
)
try:
with urllib.request.urlopen(req, timeout=5) as resp:
print("proxbox-api reachable:", resp.status)
except Exception as exc:
print("NOT reachable:", exc)