No description
  • JavaScript 52.1%
  • Python 42.1%
  • HTML 5.1%
  • Shell 0.4%
  • HCL 0.1%
Find a file
Chris aa9994c4e6
Some checks failed
Backend Tests / pytest (postgres) (push) Has been cancelled
Backend Tests / pytest (sqlite) (push) Has been cancelled
docs(memory): Session 754 – GitHub-Push v1.105.4-beta + Issue #2 geschlossen
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 21:02:08 +02:00
.claude feat(PROJ-109): 'Angemeldet bleiben' – Opt-in Login-Persistenz 2026-07-10 23:27:04 +02:00
.githooks chore(PROJ-61): tooling (license_config.py, inject_license_headers.py, pre-commit hook) 2026-05-19 11:57:43 +02:00
.github fix(PROJ-99): BUG-99-1/-2 — re-declare export-dropped image ENV in systemd units 2026-06-25 20:50:35 +02:00
.kimi fix(repo): tote Worktree-Gitlinks entfernen (brachen git status / Source-Control) 2026-06-27 19:34:34 +02:00
ansible feat(network): Netzwerk-Interface (Bridge + SDN-VNet) in Provisioning & Stacks → v1.90.0-beta 2026-06-15 12:32:27 +02:00
backend fix(backups): leere Backup-Storage-Liste – Datastore.Audit für Viewer + Read-Fallback 2026-07-16 22:17:43 +02:00
data_bak 37 2026-05-19 21:29:32 +02:00
docs fix(backups): leere Backup-Storage-Liste – Datastore.Audit für Viewer + Read-Fallback 2026-07-16 22:17:43 +02:00
examples/starter-pack feat(starter-pack): optionale statische Netzkonfig im Debian-13-minimal-Build (DHCP bleibt Default) 2026-07-03 15:27:22 +02:00
features docs(PROJ-104): /requirements Support-Tickets – 12 Leitentscheidungen (Core, ressourcen-gebunden) 2026-07-16 21:45:44 +02:00
frontend fix(backups): leere Backup-Storage-Liste – Datastore.Audit für Viewer + Read-Fallback 2026-07-16 22:17:43 +02:00
lxc fix(PROJ-99): BUG-99-1/-2 — re-declare export-dropped image ENV in systemd units 2026-06-25 20:50:35 +02:00
memory docs(memory): Session 754 – GitHub-Push v1.105.4-beta + Issue #2 geschlossen 2026-07-22 21:02:08 +02:00
node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709 chore: fix typo licence@ → license@ in contact e-mail (157 files) 2026-05-23 00:29:03 +02:00
packer chore: Publish-Tooling + Sidebar-Fix + kickstart95 entfernt 2026-05-20 10:22:20 +02:00
plus-publish fix(backups): leere Backup-Storage-Liste – Datastore.Audit für Viewer + Read-Fallback 2026-07-16 22:17:43 +02:00
site feat(PROJ-98): sichtbares Label „Demo" → „Tech-Preview" (Banner, Toast, Hinweis) 2026-06-19 19:19:39 +02:00
test-results deploy(PROJ-11): Deploy Playbooks-Kategorisierung (v1.5.0) 2026-04-26 23:22:10 +02:00
tools feat(install): rootless-Podman-Installer-Skript einpflegen (+ Whitelist + README) 2026-07-03 20:14:52 +02:00
.dockerignore 30 2026-04-30 13:23:13 +02:00
.env.example chore: .env.example bereinigt + docker-compose image-URL korrigiert 2026-05-20 11:33:33 +02:00
.env.postgres.example fix(PROJ-71): add .env.postgres.example + make POSTGRES_DB/USER configurable (BUG-71-2/3) 2026-05-23 22:53:39 +02:00
.gitignore fix(repo): tote Worktree-Gitlinks entfernen (brachen git status / Source-Control) 2026-06-27 19:34:34 +02:00
AGENTS.md 42 2026-05-29 21:11:53 +02:00
alembic.ini 21. Big Changes 2026-04-27 09:24:30 +02:00
caddy-beispiel.sh 2 2026-04-24 13:38:23 +02:00
Caddyfile 10 2026-04-24 22:03:00 +02:00
CLAUDE.md docs(claude): Grundregel verschriftlichen – Session-Memories ins Projekt-Repo 2026-06-29 19:19:24 +02:00
COMMERCIAL.md docs(commercial): Core-vs-Plus-Feature-Tabelle an README angeglichen (v1.105.0-beta-Stand) 2026-07-16 14:55:29 +02:00
conftest.py feat(PROJ-60): Backend Plus-Proxy-Refactor (AGPL-saubere Plus-Trennung) 2026-05-15 22:31:42 +02:00
CONTRIBUTING.md docs: CONTRIBUTING.md + GitHub issue templates – make sole-maintainer posture explicit and route reporters away from in-issue code suggestions 2026-05-24 19:57:17 +02:00
cutetux_zustimmung_issues_3-4_1.png 39 2026-05-24 19:25:13 +02:00
cutetux_zustimmung_issues_3-4_2.png 39 2026-05-24 19:25:13 +02:00
docker-compose.override.yml.example feat(PROJ-67): Security-Hardening Phase 1 vollständig implementiert 2026-05-19 12:19:15 +02:00
docker-compose.postgres.yml docs(compose): Container-Image-Registry (Core/Plus) dokumentieren 2026-06-27 19:53:17 +02:00
docker-compose.yml docs(compose): Container-Image-Registry (Core/Plus) dokumentieren 2026-06-27 19:53:17 +02:00
Dockerfile fix(PROJ-93): Build-Dummy-SECRET_KEY für ansible-doc-Cache-RUN im Dockerfile 2026-06-18 10:28:30 +02:00
entrypoint.sh feat(PROJ-76): Phase 2a backend + image-bundling (OpenTofu engine foundation) 2026-06-04 20:16:17 +02:00
KIMI.md chore: add KIMI.md context file + extend pytest allowlist in settings 2026-05-28 14:56:39 +02:00
konzept.md docs(PROJ-104): /requirements Support-Tickets – 12 Leitentscheidungen (Core, ressourcen-gebunden) 2026-07-16 21:45:44 +02:00
LICENSE feat(PROJ-61): legal foundation (AGPLv3 §7(b), LICENSE-PLUS, TRADEMARK.md, COMMERCIAL.md, README.md) 2026-05-19 11:54:35 +02:00
LICENSE-PLUS docs(PROJ-61): LICENSE-PLUS Modell-B-Framing – Lizenzdatei als ausgestelltes Instrument 2026-06-16 21:49:59 +02:00
p3logo.png 37 2026-05-19 21:29:32 +02:00
p3portal-podman-install.sh fix(install): volumes wiederherstellen (in S725-Bereinigung fälschlich entfernt) 2026-07-04 19:57:30 +02:00
p3portal_landing_exact_style.html 30 2026-04-30 13:23:13 +02:00
plus.enc feat(PROJ-17): Plus-Lizenz-Verifikation via Envelope Encryption 2026-04-29 22:42:48 +02:00
podman-compose.host-mode.yml fix: mount ansible/+packer/ read-write to enable starter-pack auto-copy 2026-05-21 14:43:17 +02:00
README.md docs(readme): Core+Plus README auf v1.105.0-beta-Stand (seit letztem GitHub-Push) 2026-07-16 14:54:12 +02:00
SECURITY.md chore(PROJ-72): Phase B — Plus aus öffentlichem github/-HEAD entfernt (v1.75.0-beta) 2026-05-26 17:58:23 +02:00
smoke-test-proj64.sh feat(PROJ-64): Approval-Workflow-Plus-Migration – Backend vollständig 2026-05-17 21:31:24 +02:00
status.md 14 2026-04-26 10:12:23 +02:00
THIRD-PARTY-LICENSES.md docs: interne PROJ-Bezeichnungen aus oeffentlichen Dateien entfernen + Stacks in READMEs 2026-06-06 19:57:34 +02:00
todo.md 2 2026-04-24 13:38:23 +02:00
TRADEMARK.md chore: unify licence → license spelling in public docs 2026-05-23 10:10:48 +02:00
Unbenannt.xcf 37 2026-05-19 21:29:32 +02:00

P3 Portal

Core: AGPLv3 Plus: Source-Available

This is the Core repository (100 % AGPLv3). The Plus Edition source moved out of this repository with v1.75.0-beta and lives at https://github.com/P3Portal-org/p3portal-plus. See Core vs. Plus below.

P3 Portal is a self-hosted web platform for managing Proxmox VE — a live cluster dashboard, Ansible/Packer automation, networking & firewall management, VM/LXC lifecycle and fine-grained access control. It runs as a single Docker/Podman container; users are managed locally in the portal, and Proxmox API tokens are used by the backend to execute operations on the cluster. An optional Plus edition extends it with declarative Stacks (infrastructure as code via OpenTofu) and more — see Core vs. Plus.

Cluster dashboard

What it does (Core)

  • Cluster dashboard — live overview of nodes, VMs, LXC containers, CPU/RAM/storage
  • Automation — parametrised Ansible playbooks with live logs plus in-guest runs via dynamic inventory; Packer template builds from .pkr.hcl
  • Networking & firewall — Linux bridges/VLANs, SDN (zones / VNets / subnets), datacenter / node / VM firewall rules, security groups, IP sets
  • IP address management (IPAM) — IP pools per network with a best-effort free-IP suggestion at deploy time
  • VM/LXC lifecycle — detail pages, power & snapshots, clone / migrate / convert-to-template, disk attach/resize, backup-job management, ISO & LXC template management (Image Factory)
  • High availability — manage Proxmox HA rules/groups and resources on clustered installations
  • Access control — fine-grained per-VM/LXC RBAC with custom role presets, resource ownership (incl. adopting externally-created VMs), teams and granular admin delegation; permission-aware UI throughout
  • Security & access — local users, two-factor authentication (TOTP), installable PWA desktop app
  • Job history & API — every run logged with full output, filterable and searchable; scoped API keys, external jobs API, webhooks
  • Notifications, theming & i18n — notification hub, built-in themes, DE/EN

The Plus edition adds declarative Stacks (VMs / LXC / networks / firewall as code via OpenTofu), an interactive topology view, scheduled jobs & auto-snapshots, config snapshots, resource pools with quotas, a 4-eyes approval workflow, multi-cluster dashboards, Git-sync, template replication across nodes, a stateful IPAM (persistent allocations & network grants), alert presets (SMTP / webhook), a theme editor, and visual editors for Packer & Ansible. Full breakdown: Core vs. Plus.

Everything needed to run (Python, Ansible, Packer, the React frontend — plus OpenTofu in the Plus image) is bundled. Nothing needs to be installed on the host.

Playbook form Packer build
Setup wizard

Requirements

  • Docker ≥ 24 or Podman ≥ 4.4 with podman-compose
  • A reachable Proxmox VE instance (≥ 7.x)
  • Proxmox API tokens for the portal service accounts (see Proxmox Setup)

Deployment

1 — Clone and prepare

git clone https://github.com/P3Portal-org/p3portal.git
cd p3portal

cp .env.example .env
$EDITOR .env

2 — Configure .env

Minimum required values:

SECRET_KEY=<random string, at least 32 characters>
TZ=Europe/Berlin

Generate a secure SECRET_KEY:

python3 -c "import secrets; print(secrets.token_hex(32))"
# or
openssl rand -hex 32

The admin account is created through the Setup Wizard on first start — no credentials needed in .env.

See .env.example for the full list of options including Proxmox tokens, Packer settings, and the optional audit log.

3 — Get the image

The default docker-compose.yml and podman-compose.host-mode.yml reference ghcr.io/p3portal-org/p3portal:latest — pre-built Core images (100 % AGPLv3) published on GitHub Container Registry. No local build needed for the default path:

# Docker
docker pull ghcr.io/p3portal-org/p3portal:latest

# Podman
podman pull ghcr.io/p3portal-org/p3portal:latest

Available Core tags:

Tag Licence
ghcr.io/p3portal-org/p3portal:latest / :core 100 % AGPLv3

Versioned tags like :1.75.0-beta are also published — use them to pin a specific release.

For the Plus Edition image see the Core vs. Plus section below.

3a — Build locally (optional)

If you want to build the Core image yourself (e.g. for development or behind an air-gapped network):

docker build -t p3portal:local .

To verify that the build contains no Plus artifacts:

./tools/verify-core-build.sh p3portal:local

4 — Start

# Docker Compose (bridge network — recommended default)
docker compose up -d

# Podman Compose (bridge network — recommended default)
podman-compose up -d

# Podman Compose — host network (required for Packer HTTP-preseed builds)
podman-compose -f podman-compose.host-mode.yml up -d

The portal starts on https://<host>:8443. A self-signed TLS certificate is generated automatically on first start — accept the browser warning or replace the certificate (see below).

Automated rootless Podman install (optional)

On a fresh Debian/Ubuntu host you can skip the manual steps above with the bundled installer. It installs Podman, creates a dedicated non-root user, writes a self-contained compose stack (Valkey + portal + celery worker) and enables it as a lingering systemd --user service:

sudo ./p3portal-podman-install.sh

It prompts for the app name, image edition (Core/Plus), SECRET_KEY, and the HTTPS + Packer-HTTP ports. Everything is written under /home/<app-user>/podman/<app-name>/.

Or run it straight from the repository. The installer needs root and is interactive, so use process substitution — a plain curl … | bash pipe would feed the script to bash's stdin and break the prompts:

sudo bash <(curl -sSL https://raw.githubusercontent.com/P3Portal-org/p3portal/main/p3portal-podman-install.sh)

Prefer to grab it first? Download, then run (the file is on disk, so you can inspect it beforehand):

wget https://raw.githubusercontent.com/P3Portal-org/p3portal/main/p3portal-podman-install.sh
sudo bash p3portal-podman-install.sh

Swap main for a released tag (e.g. v1.105.0-beta) in the URL for a reproducible install.

5 — Setup wizard

Open https://<host>:8443 in your browser. The built-in wizard guides you through:

  1. Licence info (Core is free, no key needed)
  2. Database selection (SQLite default / PostgreSQL optional)
  3. Admin account
  4. Proxmox node connection
  5. API tokens
  6. Packer token (optional)
  7. Done — auto-login

Volumes & persistent data

All state lives in ./data/, which is mounted into every container:

Path Contents
data/portal.db SQLite database — jobs, config, users
data/*.log Job output and Proxmox audit logs
data/valkey.pwd Auto-generated Valkey password (created on first start)

Mount your own playbooks and Packer definitions via the existing volume declarations in docker-compose.yml:

volumes:
  - ./ansible:/app/ansible      # Ansible playbooks + meta.yaml
  - ./packer:/app/packer        # Packer .pkr.hcl + meta.yaml
  - ./data:/app/data            # logs & database (persistent)

Both ansible/ and packer/ are mounted read-write so the portal's upload features (playbook bundles, Packer templates) can drop files there at runtime.

Starter pack

Ready-to-use example playbooks and Packer templates live in examples/starter-pack/ and are included in the image. Copy them into your mounted ansible/ and packer/ directories to get going quickly — they show all meta.yaml patterns documented in docs/meta-yaml-reference.md.


TLS / HTTPS

Default — self-signed certificate

The container generates ssl/portal.crt + ssl/portal.key on first start and serves directly on port 8443 via TLS. To use your own certificate, place portal.crt and portal.key in ./ssl/ before starting.

Optional — Caddy reverse proxy

Generate a self-signed cert for your server IP and let Caddy terminate TLS:

SERVER_IP=$(hostname -I | awk '{print $1}')
mkdir -p ssl
openssl req -x509 -nodes -newkey rsa:2048 \
    -keyout ssl/portal.key -out ssl/portal.crt \
    -days 3650 -subj "/CN=p3portal.local" \
    -addext "subjectAltName=IP:${SERVER_IP}"

A Caddyfile is included in the repository for reference.


Network modes

The default setup uses a bridge network (portal-net), which is right for most LAN/VPN environments.

If you need host networking — for example when Packer's HTTP-preseed server (port 8103) must be reachable directly by Proxmox VMs during a template build — two options are available:

Docker Compose — copy and activate the override example:

cp docker-compose.override.yml.example docker-compose.override.yml
# adjust if needed, then:
docker compose up -d

Podman Compose — use the dedicated host-mode file:

podman-compose -f podman-compose.host-mode.yml up -d

After switching to host mode, set the Packer HTTP IP in System Settings to the IP address of the host machine.

P3 Portal is designed for LAN / VPN environments. Exposing it to the public internet is outside the supported scope.


Updating

Default (pulling pre-built images from GHCR):

# Docker
docker compose pull && docker compose up -d

# Podman
podman-compose pull && podman-compose up -d

If you build locally instead:

git pull
docker build -t p3portal:local .
docker compose up -d   # adjust image: in docker-compose.yml to p3portal:local

Database schema migrations run automatically on startup.

PostgreSQL (optional)

SQLite is the default and works well for single-server deployments. For multi-user team setups or when you need concurrent write access, PostgreSQL 14+ is supported as a production database.

Quick setup — add to .env and start with the overlay:

# .env
DB_URL=postgresql+asyncpg://p3portal:changeme@postgres:5432/p3portal
POSTGRES_PASSWORD=changeme

# start
docker-compose -f docker-compose.yml -f docker-compose.postgres.yml up -d

The overlay adds a postgres:17-alpine service and a postgres-backup sidecar that runs nightly pg_dump into ./data/db-backup/ (keeps the last 7 dumps by default).

See docs/postgres-deployment.md for full details including backup, restore, and pool tuning.


Proxmox Setup

The portal needs up to four API tokens with different privilege levels. The first three are mandatory; the packer token is only required if you want to use the Image Factory / Packer builds.

Token Role Purpose
portal-viewer@pve!portal-viewer PVEAuditor Read cluster state
portal-operator@pve!portal-operator PVEVMAdmin Ansible playbook execution
portal-admin@pve!portal-admin Administrator Full management actions
portal-packer@pve!portal-packer (optional) custom role Packer template builds + ISO download

The portal-packer role needs VM.Allocate, VM.Clone, Datastore.AllocateTemplate, VM.Config.Disk, and on PVE ≥ 8 also Sys.AccessNetwork (required by Proxmox's download-url endpoint).

Step-by-step pveum instructions are in docs/proxmox-setup.md. Per-endpoint token usage is documented in docs/token-usage.md.


Core vs. Plus

Two independent image streams. Choose at pull time.

Image Built from Licence
ghcr.io/p3portal-org/p3portal:latest (= :core) this repository (AGPLv3) 100 % AGPLv3
ghcr.io/p3portal-org/p3portal-plus:latest https://github.com/P3Portal-org/p3portal-plus (Source-Available) AGPLv3 (Core) + LICENSE-PLUS (Plus modules)

The Plus image embeds the same Core code plus the proprietary backend/plus/ / frontend/src/plus/ modules. Without a plus.lic runtime key the Plus features stay locked and the image behaves like Core. With a valid key the features below unlock.

Feature Core image Plus image (no key) Plus image (key)
Proxmox cluster dashboard
Ansible playbook runner
Packer template builder
Job history & live logs
Network management (Linux bridges & VLANs)
SDN management (zones / VNets / subnets)
Proxmox firewall (datacenter / node / VM rules, security groups, IP sets)
VM disk management (attach / resize / remove)
VM / LXC clone, migrate & convert-to-template
High-availability management (HA rules / groups & resources)
IP pools & free-IP suggestion (Simple-IPAM)
Two-factor authentication (TOTP)
30-day Plus trial (one-time, unlocks all Plus features)
Scheduled jobs ✓ up to 3
User accounts ✓ up to 6 ✓ up to 6
User groups & teams ✓ up to 3 ✓ up to 3
Role presets ✓ up to 5 ✓ up to 5
Resource ownerships (VM / LXC) ✓ up to 10 ✓ up to 10
Multi-node / multi-cluster
Resource pools with quotas
Approval workflow (4-eyes)
Per-node permission scopes (view tasks / view backups / upload ISO)
Playbook permission whitelists
Alert presets & SMTP / webhook
Theme editor (colour picker)
Git sync for playbooks & Packer
VM / LXC config snapshots (JSON snapshot + diff + restore)
Auto-snapshots on schedule (Proxmox-native + config, GFS retention)
Stacks (declarative VM/LXC infrastructure via OpenTofu — plan / deploy / destroy / drift)
Stacks extras (multi-disk, cloud-init login, LXC containers, stack-private bridge & SDN networks, declarative firewall)
Cluster topology view (interactive React Flow graph)
VM dependencies & action-impact warnings
Packer visual editor (form-driven build definitions)
Ansible visual editor (schema-driven task builder)
Template replication across nodes (storage-aware)
IPAM — persistent allocations, reservation lifecycle, network grants & Stacks IP assignment

The Plus image without a key can be unlocked once for a 30-day trial (System Settings → Licence or the Setup Wizard); afterwards it falls back to Core. Upload a licence key in System Settings → Licence or through the Setup Wizard for a permanent unlock. Plus sales are currently inactive — see COMMERCIAL.md.


Development

# Backend (with hot-reload)
pip install -r backend/requirements.txt
uvicorn backend.main:app --reload --port 8443

# Frontend (Vite dev server)
cd frontend && npm install && npm run dev

# Tests
cd backend && pytest
cd frontend && npm run lint && npm run build

Contributing & Bug Reports

P3 Portal is an early beta. External pull requests are not accepted at this time — incoming PRs will be closed automatically by a workflow. Please use GitHub Issues for bug reports, feature ideas and questions.

Contribution policy may change after beta. Until then: code changes come from the maintainer.


Built with AI assistance

Significant portions of this codebase were written with the help of AI coding assistants (primarily Anthropic Claude). The maintainer designs the architecture, drives every feature, reviews each change and is responsible for the resulting code and its licensing.

This disclosure is made in the interest of transparency. It does not affect the licence terms: this repository's source is covered by LICENSE (AGPLv3) as specified below.


Licensing

Path Licence
backend/ (everything in this repo) AGPLv3
frontend/src/ (everything in this repo) AGPLv3
backend/plus/ / frontend/src/plus/ Stubs only in this repo. Full source lives in p3portal-plus under LICENSE-PLUS.
  • LICENSE — AGPLv3 + §7(b) Author Attribution (governs all source files in this repository)
  • LICENSE-PLUS — Source-Available, key-required, no redistribution (governs source files in the separate p3portal-plus repository, and historical Plus commits in this repository's git history)
  • COMMERCIAL.md — Plus licence details and feature comparison
  • TRADEMARK.md — Trade names, author pseudonym, domain notice

p3portal.org