# Procedure: Deploy PegaProx on Docker Swarm **Scope:** Deploy PegaProx (Proxmox VE cluster manager) as a Docker Swarm service on MK7. **Author:** F.R.I.D.A.Y. **Date:** 2026-05-31 **Prerequisites:** MK7 Swarm manager active, `traefik-public` overlay network exists. --- ## 1. Create Swarm Compose File Save as `/tmp/pegaprox_swarm.yml` on MK7: ```yaml version: "3.8" services: pegaprox: image: pegaprox/pegaprox:latest deploy: mode: replicated replicas: 1 placement: constraints: - node.role == manager ports: - target: 5000 published: 5000 mode: host protocol: tcp - target: 5001 published: 5001 mode: host protocol: tcp - target: 5002 published: 5002 mode: host protocol: tcp networks: - traefik-public volumes: - pegaprox-config:/app/config environment: - PEGAPROX_DEBUG=0 volumes: pegaprox-config: driver: local networks: traefik-public: external: true ``` > **Critical:** `mode: host` is required. `ingress` mode breaks WebSocket VNC/SSH consoles because Swarm ingress routing does not support WebSocket upgrade properly. --- ## 2. Deploy Stack ```bash ssh jarvis@mk7.ai.home docker stack deploy -c /tmp/pegaprox_swarm.yml pegaprox ``` Verify: ```bash docker service ls | grep pegaprox docker ps | grep pegaprox ``` --- ## 3. Verify Service Health ```bash # HTTPS API curl -sk https://192.168.7.7:5000/api/health # Check container logs docker logs $(docker ps -q -f name=pegaprox) ``` Expected: `{"status":"ok"}` --- ## 4. First Login & Password Change 1. Open `https://192.168.7.7:5000` 2. Login with default credentials: - Username: `pegaprox` - Password: `admin` 3. System will force password change on first login 4. API returns: `{"security_warning":"DEFAULT_PASSWORD","requires_password_change":true}` --- ## 5. API Notes for Automation ### CSRF Protection All state-changing API calls (POST/PUT/PATCH/DELETE) must include: ``` X-Requested-With: XMLHttpRequest ``` Exempt paths (no CSRF header needed): - `/api/auth/login` - `/api/auth/setup` - `/api/auth/oidc/*` - `/api/auth/check` - `/api/auth/validate` - `/api/auth/logout` - `/api/health` - `/api/webauthn/auth/begin` ### Add Cluster ```bash curl -sk -X POST https://192.168.7.7:5000/api/clusters \ -b cookies.txt \ -H "Content-Type: application/json" \ -H "X-Requested-With: XMLHttpRequest" \ -d '{ "name": "MK33", "host": "192.168.7.33", "user": "root@pam", "pass": "YOUR_PVE_PASSWORD" }' ``` > **CRITICAL:** `host` must be **bare IP only**. Do NOT append `:8006`. PegaProx appends the port internally. Supplying `192.168.7.33:8006` causes URL parse failure: `Failed to parse: https://[192.168.7.33:8006]:8006/...` --- ## 6. Backup Volume ```bash # Backup PegaProx config + DB docker run --rm -v pegaprox_pegaprox-config:/src -v /tmp:/dst alpine \ tar czf /dst/pegaprox-config-$(date +%Y%m%d).tar.gz -C /src . ``` --- ## 7. Known Issues | Issue | Cause | Fix | |-------|-------|-----| | WebSocket VNC/SSH broken | Swarm `ingress` mode strips upgrade headers | Use `mode: host` | | URL parse error on add-cluster | `:8006` appended to host field | Use bare IP only | | CSRF 403 on API calls | Missing `X-Requested-With` header | Add header to all state-changing calls | | Self-signed cert warning | No CA-signed cert deployed | Accept in browser or deploy custom cert | --- ## Rollback ```bash ssh jarvis@mk7.ai.home docker stack rm pegaprox docker volume rm pegaprox_pegaprox-config # WARNING: destroys all data ``` --- *Last updated: 2026-05-31*