Skip to content

Installation

This page documents supported ways to run proxbox-api.

Requirements

  • Python 3.11+
  • uv (recommended) or pip
  • Network access to NetBox and Proxmox targets

All Docker images are Alpine-based (smaller footprint). Three variants are available:

Variant Tags Description
Raw (default) latest, <version> Pure uvicorn, HTTP only. Smallest image.
Nginx latest-nginx, <version>-nginx nginx terminates HTTPS via mkcert; proxies to uvicorn.
Granian latest-granian, <version>-granian Granian (Rust ASGI server) with native TLS via mkcert.

Raw image — HTTP only (default)

Simplest option. No proxy in front, plain HTTP. Ideal for local development or behind your own reverse proxy.

docker pull emersonfelipesp/proxbox-api:latest
docker run -d -p 8000:8000 --name proxbox-api emersonfelipesp/proxbox-api:latest

Service URL:

Nginx image — HTTPS with mkcert

nginx terminates HTTPS using auto-generated mkcert certificates and proxies to uvicorn inside the container.

docker pull emersonfelipesp/proxbox-api:latest-nginx
docker run -d -p 8443:8000 --name proxbox-api-nginx \
  emersonfelipesp/proxbox-api:latest-nginx

Service URL:

Connecting netbox-proxbox to the nginx image

The nginx image is HTTPS-only — plain HTTP requests to the TLS port return a JSON 400 body with {"error":"plain_http_on_https_port", ...} (rendered from nginx's internal 497 code). When configuring the FastAPI Endpoint in the NetBox netbox-proxbox plugin, set:

Field Value
Use HTTPS ✓ enabled
Verify SSL ✗ disabled (when using the bundled mkcert certificate)
Port the host port mapped to container 8000 (typically 8800 or 8443)

The Use HTTPS and Verify SSL toggles are independent in netbox-proxbox >= 0.0.16 — see issue #352 for context. Earlier plugin releases couple the two flags, which makes the nginx-image + self-signed-cert combination unreachable.

Granian image — HTTPS with mkcert (no nginx)

Granian is a Rust-based ASGI server with native TLS and HTTP/2. A single process handles everything — no nginx or supervisord required.

docker pull emersonfelipesp/proxbox-api:latest-granian
docker run -d -p 8443:8000 --name proxbox-api-granian \
  emersonfelipesp/proxbox-api:latest-granian

Service URL:

Docker runtime environment variables

Common to all images (raw, nginx, granian):

Variable Default Description
PORT 8000 Port the server listens on
PROXBOX_BIND_HOST 0.0.0.0 Address the server binds to. Set to :: for IPv4 + IPv6 dual-stack. Honored by the raw and granian images; the nginx image listens on both stacks unconditionally.

mkcert-specific (only for the nginx and granian images):

Variable Default Description
MKCERT_CERT_DIR /certs Directory where certificates are stored
MKCERT_EXTRA_NAMES Extra SANs (comma or space separated), e.g. proxbox.lan,10.0.0.5
CAROOT Mount a volume here to persist the local CA across restarts

Example with extra SANs:

docker run -d -p 8443:8000 --name proxbox-api-tls \
  -e MKCERT_EXTRA_NAMES='myhost.local,192.168.1.10' \
  emersonfelipesp/proxbox-api:latest-nginx

Mounting custom certificates

Both the nginx and granian images detect pre-existing certificates at startup. If cert.pem and key.pem are already present inside $MKCERT_CERT_DIR (default /certs), mkcert generation is skipped entirely — the container uses those files as-is. This lets you mount your own CA-signed, Let's Encrypt, or corporate certificates without any special flags.

docker run -d -p 8443:8000 --name proxbox-api-nginx \
  -v ./certs:/certs:ro \
  emersonfelipesp/proxbox-api:latest-nginx

The ./certs directory must contain at minimum:

File Description
cert.pem PEM-encoded certificate (may be a full chain)
key.pem PEM-encoded private key (PKCS#1 or PKCS#8)

Docker Compose example:

services:
  proxbox-api:
    image: emersonfelipesp/proxbox-api:latest-nginx
    container_name: proxbox-api
    restart: unless-stopped
    ports:
      - "8443:8000"
    volumes:
      - ./certs:/certs:ro

Granian image and PKCS#8 keys

Granian's TLS layer requires the private key in PKCS#8 format. The entrypoint handles this automatically:

  1. If key-pkcs8.pem is present in the mounted directory → use it directly.
  2. If key-pkcs8.pem is absent and the directory is writable → convert key.pem in place and write key-pkcs8.pem there.
  3. If key-pkcs8.pem is absent and the directory is read-only → convert and write to /tmp/key-pkcs8.pem (ephemeral; not persisted across container restarts).

To pre-convert your key and avoid the /tmp fallback:

openssl pkcs8 -topk8 -nocrypt -in ./certs/key.pem -out ./certs/key-pkcs8.pem

Then mount the directory containing all three files (cert.pem, key.pem, key-pkcs8.pem).

Binding to IPv6 / dual-stack

To listen on both IPv4 and IPv6, set PROXBOX_BIND_HOST=:::

docker run -d -p 8000:8000 -e PROXBOX_BIND_HOST=:: \
  emersonfelipesp/proxbox-api:latest

Docker Compose quoting caveat

In Compose environment: list-form, values are taken verbatim — the quotes are NOT stripped — so - PROXBOX_BIND_HOST="::" ends up as the literal 4-character string "::" inside the container, which used to crash binding with [Errno -2] Name does not resolve. The container now sanitizes surrounding quotes defensively, but the recommended forms are:

environment:
  - PROXBOX_BIND_HOST=::          # list-form: NO quotes
environment:
  PROXBOX_BIND_HOST: "::"         # map-form: YAML strips the quotes

Build from source

git clone https://github.com/emersonfelipesp/proxbox-api.git
cd proxbox-api

docker build -t proxbox-api:raw .                          # raw (default)
docker build --target nginx -t proxbox-api:nginx .         # nginx
docker build --target granian -t proxbox-api:granian .     # granian

Option 2: PyPI

The package is published to PyPI as proxbox-api.

pip install proxbox-api

Or with uv:

uv add proxbox-api

Start the server:

python -m uvicorn proxbox_api.main:app --host 0.0.0.0 --port 8000

Option 3: Local development from source

Clone repository:

git clone https://github.com/emersonfelipesp/proxbox-api.git
cd proxbox-api

Install runtime dependencies:

pip install -e .

Or use uv:

uv sync

Run API:

uv run fastapi run proxbox_api.main:app --host 0.0.0.0 --port 8000

Alternative with uvicorn:

uv run uvicorn proxbox_api.main:app --host 0.0.0.0 --port 8000 --reload

fastapi run does not expose TLS flags; for HTTPS from the app process, use uvicorn with --ssl-certfile / --ssl-keyfile below, or put nginx/Caddy in front (recommended for real certificates).

TLS without Docker

Local certificates (mkcert)

For trusted HTTPS on your own machine only:

mkcert -install
mkcert proxbox.backend.local localhost 127.0.0.1 ::1
uv run uvicorn proxbox_api.main:app --host 127.0.0.1 --port 8000 --reload \
  --ssl-keyfile=./proxbox.backend.local+3-key.pem \
  --ssl-certfile=./proxbox.backend.local+3.pem

Adjust file names to match what mkcert created.

Publicly trusted or corporate certificates

Recommended: terminate TLS in nginx or Caddy, run the API on HTTP on 127.0.0.1:8000:

uv run uvicorn proxbox_api.main:app --host 127.0.0.1 --port 8000

Point the proxy at http://127.0.0.1:8000 and set ssl_certificate / ssl_certificate_key to your PEM paths (for Let's Encrypt: fullchain.pem and privkey.pem under /etc/letsencrypt/live/<domain>/). Set X-Forwarded-Proto and related headers so the app sees the original scheme. See the repository README for a complete nginx server example.

Direct uvicorn TLS (small deployments): use the full certificate chain as --ssl-certfile and the private key as --ssl-keyfile:

uv run uvicorn proxbox_api.main:app --host 0.0.0.0 --port 8443 \
  --ssl-certfile=/etc/letsencrypt/live/api.example.com/fullchain.pem \
  --ssl-keyfile=/etc/letsencrypt/live/api.example.com/privkey.pem

Ensure the process user can read those files, and renew/reload after certificate updates.

Verify installation

Open: