Skip to main content

Installation

ProxCenter is deployed self-hosted on your own infrastructure using Docker.

Self-Hosted with Docker

Deploy ProxCenter on your own server for full control over your data and configuration.

Prerequisites

Before you begin, make sure you have:

RequirementDetails
Operating SystemLinux server (Ubuntu 22.04+, Debian 12+, or any Docker-compatible distribution)
DockerDocker Engine 24+ and Docker Compose v2+
DatabasePostgreSQL 15+ (the official Docker install provisions PostgreSQL automatically)
RAMMinimum 2 GB
Disk SpaceMinimum 10 GB (more recommended for database growth)
Ports3000 (ProxCenter web interface)
NetworkConnectivity to your Proxmox nodes on port 8006 (PVE) and/or 8007 (PBS)

Step 1: Run the installer

Get the current installation command from https://proxcenter.io, then run it on the server that will host ProxCenter:

curl -fsSL https://proxcenter.io/install/community | sudo bash

The installer provisions the Docker Compose stack, persistent volumes, PostgreSQL, and the ProxCenter application services.

Step 2: Access the dashboard

Open your browser and navigate to:

http://your-server-ip:3000

On the first launch, you will be prompted to create your admin account. This account has full access to ProxCenter and cannot be deleted.

Updating ProxCenter

For v1.4.x and later, update an existing PostgreSQL-based deployment with:

docker compose pull
docker compose up -d
info

ProxCenter uses PostgreSQL for all supported production deployments. Schema migrations run automatically on startup.

Upgrading from SQLite

SQLite support was removed in v1.4.0. Existing deployments from v1.3.x or earlier need a planned cutover to a PostgreSQL-backed v1.4 stack. See Upgrade to v1.4 before updating image tags.

Reverse Proxy and Public URL

If you expose ProxCenter behind a reverse proxy (nginx, Traefik, Caddy, HAProxy), you must tell ProxCenter what its public URL is. The frontend uses NEXTAUTH_URL from /opt/proxcenter/.env to:

  • build OIDC / SSO redirect_uri values sent to your identity provider,
  • set the Secure flag on session and CSRF cookies (auto-enabled when the URL starts with https://),
  • generate absolute links in emails and webhooks.

The installer writes NEXTAUTH_URL based on the address used at install time. If that address was the server's internal IP, the variable will hold the IP and external integrations (DUO, Okta, Entra ID, Authentik, etc.) will receive the IP as the callback URL.

Set the public URL

  1. Edit /opt/proxcenter/.env and replace the NEXTAUTH_URL line with the public FQDN that users will reach in their browser:

    NEXTAUTH_URL=https://proxcenter.example.com
  2. Restart the stack so the new value is picked up:

    cd /opt/proxcenter && docker compose up -d

Nginx example

server {
listen 443 ssl http2;
server_name proxcenter.example.com;

# ssl_certificate / ssl_certificate_key ...

location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

The Upgrade / Connection headers are required for the noVNC and xterm.js console WebSocket streams to flow through the proxy.

tip

Always set NEXTAUTH_URL before configuring OIDC. The Redirect URI displayed on the OIDC settings page is derived from it. If you flip the URL afterwards, you also have to update the Redirect URI in your identity provider so they match exactly (scheme, host, port, no trailing slash mismatch).

Rate limiting and request filtering

ProxCenter is a single-page app. On a cold load or a hard refresh (Ctrl+Shift+R) the browser requests a large burst of JavaScript chunks from /_next/static/, often more than a hundred files at once. Web Application Firewalls and rate limiters (CrowdSec, nginx limit_req, ModSecurity, Cloudflare) frequently mistake this burst for abuse and answer with HTTP 429 or 403. When that happens the app never finishes loading and users get stuck on an endless spinner, while the same deployment works fine on the local network where no proxy sits in front.

Two rules keep ProxCenter working behind a security proxy.

1. Do not rate-limit static assets. Exempt /_next/static/ from any request-rate limiting. These files are content-hashed and immutable, so they are safe to serve without a cap.

# Exempt the static chunk burst from rate limiting (CrowdSec, limit_req, ...)
location /_next/static/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
# no limit_req / appsec rule here
}

Also make sure the proxy serves over HTTP/2 (listen 443 ssl http2; in the example above), which multiplexes the burst over a single connection instead of opening dozens of them.

2. Do not apply generic WAF filtering to the sign-in flow. The OIDC / SSO sign-in redirects the browser to your identity provider and back to ProxCenter's callback with long, random state and code values in the query string. Aggressive WAF rules routinely block these legitimate requests. If sign-in hangs or loops only when accessed through the proxy, relax these in particular:

  • Empty User-Agent blocks. Some clients and intermediate hops send no user agent. Returning 403 on an empty UA breaks legitimate logins.
  • HTTP method allow-lists that are too narrow. Allow at least GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH.
  • Generic "SQL injection" or "dangerous character" patterns matched against the query string. OIDC state and code values contain substrings that trip these rules. Match such patterns against POST bodies only, or exempt the auth callback path.
warning

If login works on the local network but hangs or loops only when users come through the reverse proxy, the cause is almost always the proxy filtering the OIDC callback or rate-limiting the static chunk burst, not ProxCenter itself. ProxCenter does no application-level rate limiting.

Security headers

ProxCenter already sends a baseline set of response headers from the application itself: X-Content-Type-Options: nosniff, X-Frame-Options: SAMEORIGIN, Referrer-Policy: strict-origin-when-cross-origin and Permissions-Policy: camera=(), microphone=(), geolocation=(). You do not need to add those at the proxy. If you do set X-Frame-Options at the proxy (for example a stricter DENY), add proxy_hide_header X-Frame-Options; first to avoid a duplicate header.

The one header ProxCenter does not set by default is a Content Security Policy, because the correct value depends on which external resources your deployment allows. The policy below loads everything the UI needs and nothing more. Add it inside the server { ... } block next to the location / from the example above:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https://*.tile.openstreetmap.org https://*.basemaps.cartocdn.com https://flagcdn.com; connect-src 'self' https://nominatim.openstreetmap.org https://api.github.com; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none';" always;

What each non-'self' source is for:

SourceUsed by
script-src 'unsafe-inline'Next.js inline hydration scripts, and the inline scripts in the noVNC and SPICE console pages
style-src 'unsafe-inline'MUI / Emotion inject <style> tags at runtime
https://fonts.googleapis.com, https://fonts.gstatic.comGoogle Fonts stylesheet and font files
https://*.tile.openstreetmap.org, https://*.basemaps.cartocdn.comMap tiles on the Topology and datacenter maps
https://flagcdn.comCountry flags on the maps
img-src data: blob:Console live-preview thumbnails, and PNG / Excel exports
https://nominatim.openstreetmap.orgReverse geocoding when adding or editing a connection with coordinates
https://api.github.comRelease notes shown in the About dialog

A few things worth knowing:

  • The VNC, SPICE and serial consoles connect over wss:// to the same origin (proxied through nginx), so connect-src 'self' already covers them. There is no direct browser-to-node connection. If a console fails to connect on an older browser, add your explicit origin (for example wss://proxcenter.example.com) to connect-src.
  • frame-ancestors 'none' is the modern equivalent of X-Frame-Options: DENY and is safe to keep: the consoles open in popup windows, never in an iframe.
  • script-src 'unsafe-inline' is currently required: Next.js emits inline bootstrap scripts to hydrate the UI, and the console pages carry their connection logic inline. 'unsafe-eval' is not needed by the production image. A nonce-based policy that would let you drop 'unsafe-inline' is on the roadmap.
Roll it out safely

Deploy the policy as Content-Security-Policy-Report-Only first, browse the consoles, the Topology and datacenter maps, and the About dialog, then watch the browser DevTools console for violations. Once it is clean, rename the header to Content-Security-Policy to enforce it.

Production Checklist

Before exposing ProxCenter to users, verify:

  • The server can reach Proxmox VE on port 8006 and Proxmox Backup Server on port 8007.
  • PostgreSQL data is stored on a persistent volume or managed database.
  • Docker logs are collected by your monitoring system.
  • Backups cover the PostgreSQL volume and ProxCenter configuration.
  • A reverse proxy handles TLS if the web UI is exposed outside a trusted network.
  • A Content Security Policy is set at the reverse proxy (see Security headers).
  • The first admin account is stored in your access management process.
  • Enterprise deployments have the license key available during bootstrap.

Service Layout

A standard Docker deployment contains:

ServicePurpose
FrontendWeb UI and API routes exposed on port 3000
OrchestratorBackground jobs, Proxmox polling, alerts, reports and automation
PostgreSQLApplication database for users, settings, tenants, vDCs and operational metadata
WeasyPrintPDF rendering sidecar for report generation

Uninstalling

To stop and remove ProxCenter (data is preserved in the Docker volume):

docker compose down

To remove everything including data:

docker compose down -v

Post-Installation Steps

After installation:

  1. Create your admin account on first login
  2. Connect your Proxmox infrastructure -- Add your PVE and PBS instances
  3. Activate your license (optional) -- If you have an Enterprise license key, go to Settings > License and enter it
  4. Create tenants (Enterprise, optional) -- For MSP / IaaS deployments, assign whole clusters to MSP tenants or vDCs to IaaS tenants, with quotas, networks, and backup isolation
  5. Explore the dashboard -- Head to First Steps for a guided tour

Next Steps

Once ProxCenter is up and running, the next step is to connect your Proxmox infrastructure.