The Problem
ServerKit is a self-hosted server control panel that manages web applications, databases, and services on a VPS. The codebase contains 650 files with Python/Flask backend and React frontend, but critical security and licensing issues unfit for production or redistribution: privileged Docker containers with host networking, committed development secrets, hardcoded debug mode, and no license declaring usage rights.
What This Does
ServerKit consists of a React frontend (292 files in frontend/) communicating with a Python/Flask backend (264 files in backend/). The backend defines 12 API surface areas including servers.py (87 functions), docker.py (37 functions), email.py (38 functions), and environment_pipeline.py (40 functions). Execution starts from entry points like app in backend/tests/conftest.py:16 (reaches 118 functions, called by nothing else in the repo) or start in backend/app/api/git.py:64 (reaches 93 functions). A traced path shows app -> create_app [db via db.session.commit] and start -> start_gitea -> compose_up [subprocess via subprocess.run]. The internal call graph has 2,612 resolved call edges; to_dict is called from 204 places and run_privileged from 99 places, indicating high blast-radius functions any change could affect. The frontend hub frontend/src/services/api has 94 importers and 1 importer, making it a single point of failure for API calls. Twenty-eighty-four functions read/write a database, 23 perform crypto operations, 91 run external commands, 34 make outbound network calls, and 33 read/write files.
How It Is Wired
Execution flows from entry points through hub modules to infrastructure effects. The most connected frontend module is frontend/src/services/api (Ca 94, Ce 1, instability 0.01) - 94 other modules depend on it, so changes have wide-reaching impact. frontend/src/App has inverse instability (Ca 1, Ce 48, instability 0.98), meaning it receives heavy dependency but exports little, making it a fragile root. On the backend, backend/app/api/servers.py (87 functions, called from 2 files) handles group management, makes outbound network calls, performs crypto operations, and reads/writes databases. backend/app/api/docker.py (37 functions) runs external commands, makes network calls, and reads/writes files. backend/app/services/agent_registry.py (18 functions, 3 classes) manages socketio, heartbeat checks, and performs crypto operations. The docker-compose in agent/docker-compose.yml mounts the Docker socket with privileged mode, granting the container every capability including direct device access - escaping to the host is a documented one-liner. frontend/.env.development contains committed secrets (API keys, tokens) that would surface in any public clone. backend/config.py has DEBUG = True hardcoded and SECRET_KEY falls back to a 35-character literal, both critical production risks. No LICENSE file exists at the repository root, making redistribution rights undefined.
How To Use It
Setup: No official install script is documented in the repository structure. The presence of package.json and Dockerfile implies npm-based frontend build and containerized deployment. A Dockerfile exists at the root and in agent/, suggesting docker build can produce images, but no docker-compose.yml at root level coordinates the full stack.
Configuration: Environment variables are required. backend/.env.example and frontend/.env.example exist as templates, but frontend/.env.development has committed secrets that must be rotated. The backend reads DEBUG from config.py (currently hardcoded True) and SECRET_KEY with a fallback literal - both should be sourced from environment.
Running it: No single entry point command is documented. The repository has CLI scripts in backend/cli.py (functions like activate_user, create_admin, cleanup_apps), and a main.go in agent/cmd/agent/ for the agent binary. A production deployment would likely use docker compose with the agent and backend services, but the root-level docker-compose.yml is absent - only agent/docker-compose.yml exists.
Real-World Use
A typical workflow: an operator adds a WordPress site via the UI, which calls frontend/src/services/api -> backend environment_pipeline_service.py -> creates an environment pipeline entry in the database. The pipeline triggers backend/app/api/environment_pipeline.py functions to promote code/DB from staging to production. Docker containers are managed via backend/app/api/docker.py functions that run docker CLI commands. Let's Encrypt SSL is auto-managed through backend/app/api/ssl.py. If the operator needs to debug, the hardcoded DEBUG = True in backend/config.py would expose local variables and tracebacks - including database passwords - to anyone triggering an error.
Code Health & Issues
The static analysis produced 312 total findings (164 high, 148 medium, 0 low) across two categories:
Measured findings:
- [HIGH/cognitive_load] Deep nesting x54 in
frontend/src/components/ConfirmDialog.jsx,frontend/src/components/Modal.jsx,frontend/src/components/workflow/ConfigPanel.jsx(max indentation depth 8) - [HIGH/clarity] Hub module x6:
frontend/src/services/api.js(94 dependents),frontend/src/contexts/ToastContext.jsx,frontend/src/components/ConfirmDialog.jsx - [HIGH] Pin third-party GitHub Actions to commit SHA in
.github/workflows(docker/setup-qemu-action@v3, docker/setup-buildx-action@v3, docker/login-action@v3, docker/build-push-action@v5) - [HIGH] Add a LICENSE; redistribution rights undefined (no licence file at root)
- [HIGH] Drop privileged mode and host networking -
agent/docker-compose.yml(Docker socket mounted with privileged) - [HIGH] Remove committed .env and rotate credentials -
frontend/.env.development - [HIGH] Turn off debug mode and drive from environment -
backend/config.py(DEBUG = True) - [HIGH] Open a pull request instead of pushing to default branch -
.github/workflows/version-bump.yml(git push) - [HIGH] Remove hardcoded fallback for signing key -
backend/config.py(SECRET_KEY falls back to 35-character literal) - [MEDIUM] Declare least-privilege permissions for GITHUB_TOKEN in workflows
- [MEDIUM] Enable Dependabot or Renovate (3 manifests, no update bot configured)
- [MEDIUM] Pin container base image by digest in
Dockerfile(node:20-alpine, python:3.11-slim-bookworm) - [LOW] 6 lower-ranked findings
SDLC observations from structure:
- No LICENSE file at root
- Committed secrets in
frontend/.env.development - CI present (GitHub Actions) but with security hygiene issues
- Dockerfile present but base images not pinned by digest
- Lockfiles present (frontend/package-lock.json, backend/requirements.txt, agent/go.mod)
- 7 test files found, 18 doc files found
The Bottom Line
ServerKit has functional breadth - user management, Docker orchestration, WordPress deployment, SSL, DNS, firewall, backup, and email services - but production readiness is compromised by hardcoded secrets, privileged container escalation, debug mode left on, and undefined licensing. The codebase is analytically maintainable (no circular deps, resolved call graph) but suffers from deep nesting and hub-module volatility in the frontend. It should be used only after: pinning GitHub Actions SHAs, adding an explicit license, removing and rotating the committed .env, dropping privileged mode in favor of cap_add + explicit port publishing, and switching DEBUG to environment-driven control. A team comfortable with auditing and hardening an active codebase could operationalize this, but it requires immediate security remediation before any data-sensitive deployment.