Centralize backup schedule calculations and shared request/form flows, encode query values, and move repository finalization into its service. Add browser CI coverage, repair stale test fixtures, and provide opt-in request and build measurement tools.
flask-limiter picks RATELIMIT_STORAGE_URI up from app.config at init_app,
so surfacing the env var in config (only when non-empty) lets production
deployments share limit state across processes and silences the in-memory
storage warning. Unset keeps in-memory storage, matching the deliberate
single-worker gunicorn design. Documented in .env.example with probe and
mechanism tests.
config.py's parsers move to app/utils/env.py and are imported back; the
three incompatible truthiness variants collapse to one TRUTHY tuple.
Fixes the measured bug: SERVERKIT_ALLOW_PRIVATE_DOWNLOADS=on silently
read false in plugin_service (its tuple lacked 'on'); same for the pip
gate, SERVERKIT_STAGING, and SERVERKIT_DEMO_MODE. Ratchet: no new
os.environ truthiness tuples outside utils/env.py.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dev-gated (DEMO_DEPLOYS_ENABLED) scripted DeploymentJobs — success/fail-build/
long/ansi/slow scenarios driven through RunLogStream so the Deploy Console is
fully exercisable locally with no Docker or server. GET/POST
/api/v1/deployment-jobs/simulate; retry + unified-job wiring; 12 proving tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add an in-memory (single-worker) per-IP throttle that complements the per-user
account lockout: it stops password-spraying across many accounts from one IP
and prevents a single attacker draining the shared login rate-limit bucket.
- new app/services/auth_throttle_service.py — lock-guarded TTL map with
is_blocked / register_failure / reset (+ opportunistic memory sweep)
- config: AUTH_IP_MAX_ATTEMPTS (10) / AUTH_IP_WINDOW_MINUTES (15) /
AUTH_IP_BLOCK_MINUTES (15)
- wire into /login (block up front -> 429 + Retry-After BEFORE the password
check; register on bad user/password; reset on correct password),
/login-links/redeem, and the 2FA /verify endpoint
- per-user lockout and the flask-limiter 5/min decorator kept (defense in depth)
- tests: test_login_bruteforce.py (6)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rate-limit buckets, login lockout and audit-log source IPs hand-parsed the
leftmost X-Forwarded-For token — a client-controlled value — letting an
attacker rotate it to dodge per-IP limits or forge audit trails.
- config: add TRUST_PROXY_HEADERS / TRUSTED_PROXY_HOPS (+ _env_bool/_env_int)
- create_app: wrap in gated Werkzeug ProxyFix (rightmost trusted hops) before
the limiter/handlers so every remote_addr consumer sees the real client
- new app/utils/client_ip.py::get_client_ip() — the single trusted seam
- replace all six leftmost-XFF parsers (rate_limit, audit middleware,
api_key_auth, api_analytics, audit_service, ddns) with get_client_ip()
- deploy: root .env.example ships TRUST_PROXY_HEADERS=true (behind nginx);
backend/.env.example documents it off for dev
- tests: test_trusted_client_ip.py (7) incl. real flask-limiter bucket isolation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- config: is_insecure_secret() rejects any dev/placeholder key (dev-*,
jwt-secret-key*, *change-in-production*, *change-this*, empty), not just the
two exact default strings — a variant like `dev-jwt-...` can no longer boot
in production. Used in both ProductionConfig.__init__ and init_app.
- systemd unit: bind gunicorn to 127.0.0.1 by default so the raw API port is
not world-reachable (host nginx already fronts :80/:443). Override with
SERVERKIT_BIND_HOST=0.0.0.0 for setups that front it differently.
- cli break-glass: mint the token with a string identity; flask-jwt-extended
rejects a non-string `sub` at decode time with a 422, which broke every CLI
call that authenticated against the panel API.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Build packs / zero-Dockerfile deploys (C1): new BuildpackService detects the
stack from a cloned repo (Node/Python/Go/PHP/Ruby/Rust/static), produces a
transparent build plan and a generated Dockerfile, and persists the plan +
overrides on the Application. POST /api/v1/buildpacks/{detect,generate}; a
BuildpackPreview shows the detected plan + editable overrides + Dockerfile in
the create wizard and the app Build tab. Builds on the existing build_method
plumbing instead of duplicating it.
- Deployment config snapshots + diff engine (C4): ConfigurationService captures
an immutable, hashed snapshot of resolved config (env keys + masked values,
domains, image/tag, build method, volumes) at every deploy and rollback; new
DeploymentSnapshot model + /api/v1/apps/<id>/snapshots[/diff|/restore]. A
DeploymentTimeline + ConfigDiffModal surface "what changed" and one-click
restore in the app Deploy tab. Secret values are never serialized.
- Template catalog certification (C5 cont.): a whole-catalog validation test
proves all 105 declarative templates conform to the documented schema; fixed
the stale index.json (was 63/105 entries) to list every bundled template.
Migration 030 adds the buildpack columns + deployment_snapshots table. Full
backend suite: 820 passed, 14 skipped; frontend builds clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Flask middleware emitted HSTS with includeSubDomains+preload whenever not in
debug mode -- even on HTTP-only or Cloudflare-Flexible installs, where preload is
a hard-to-reverse commitment. HTTPS is intentionally optional, so HSTS is now
gated on the operator's recorded SSL choice.
- config._resolve_ssl_mode(): SERVERKIT_SSL_MODE env -> /etc/serverkit/ssl-mode
file -> safe 'insecure' default. Exposed as SSL_MODE / HSTS_ENABLED.
- security middleware sends HSTS only when HSTS_ENABLED and not debug. Behind a
proxy Flask can't distinguish real TLS from a Flexible edge via
X-Forwarded-Proto, so we trust the installer's choice, not the request scheme.
- install.sh records SERVERKIT_SSL_MODE in .env; existing installs are covered by
the /etc/serverkit/ssl-mode file. The nginx edge still emits HSTS in its own
secure server block, so secure installs are unaffected.
Proving tests in tests/test_security_headers.py. Full backend suite: 342 passed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
create_site installed WordPress at http://localhost:<port>, which WordPress
bakes in as its canonical home/siteurl — reachable on the box but useless as a
public site URL. New SiteDomainService resolves <slug>.<base_domain> (config
SITES_BASE_DOMAIN: lvh.me in dev, opt-in in prod, empty falls back to the old
localhost URL). create_site now installs at that host and provisions a primary
Domain row + nginx reverse-proxy vhost (_provision_routing, best-effort so a box
without nginx warns instead of failing). Teardown removes the vhost; clone_site
URL rewriting is generalized via _canonical_site_url so cloning stays correct
with real hostnames.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When the panel sits behind a reverse proxy / tunnel, browsers and agents
arrive from SERVERKIT_PUBLIC_URL. Without that origin in CORS_ORIGINS the
engine.io WS handshake rejects it and every Socket.IO connection 400s with
"not an accepted origin". Auto-append SERVERKIT_PUBLIC_URL (deduped,
whitespace-stripped) so operators configure the public URL in one place.
Also bumps Flask-SocketIO 5.4.1 -> 5.6.1. Recovered from a local stash.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce fallback audit logging and enrich audit tooling; add builtin extension discovery/install; and update default launcher ports and related docs/config.
Key changes:
- New middleware app.middleware.audit registers an after-request fallback that records authenticated mutating API requests when routes don't emit explicit audit logs.
- Audit model/action constants extended and AuditService enhanced (request context handling, redaction for sensitive settings, optional commit flag, sets g.audit_logged, emits events).
- Routes/services updated to create explicit audit entries for marketplace and plugin operations (create/update/publish/install/uninstall/enable/disable) and SSO/settings flows switched to use AuditService.
- Added tests for audit logging behavior and redaction (backend/tests/test_audit_log.py).
- Plugin service: added BUILTIN_EXTENSIONS_DIR, list_builtin_extensions and install_builtin_extension; plugin API endpoints to list/install builtin extensions.
- Contribution system extended to support layouts and route layout metadata; frontend wiring updated to surface standalone/custom layouts and extension routes.
- Launcher port defaults changed (backend -> 47927, frontend -> 41921). Updated backend .env.example, config CORS defaults, Dockerfiles and docker-compose to use SERVERKIT_BACKEND_PORT, and many docs/README files and frontend envs to reflect new ports.
- Minor frontend cleanups and new builtin extension example (serverkit-git) plus associated manifest and frontend re-export.
These changes improve observability/security for mutating APIs, enable opt-in builtin plugins, and align local dev/run ports with the launcher defaults.
Broad refactor and hardening across backend and frontend:
- Standardize API error responses by removing legacy `success` flags and returning concise error payloads.
- Replace inline admin decorators with centralized middleware import (admin_required) in DB and Docker APIs.
- DatabaseService: add safer MySQL execution helpers and secure user-creation flow (hex-encoding, env-pwd usage) and improve pg drop to validate identifiers.
- Models: add eager-loading (subquery) for relationships and add indexes to frequently queried columns to reduce N+1 and improve performance.
- DockerService: add structured logging and error messages for better observability when Docker commands fail.
- Config: tighten ProductionConfig cookie settings (secure, httponly, samesite).
- Frontend: migrate many .less styles to .scss, add new security UI components and API client modules, update package metadata accordingly.
- Misc: add APP_IMPROVEMENTS.md to .gitignore.
These changes improve security, reliability, observability, and frontend styling consistency.
Adds cross-server Fleet Monitor endpoints and models, plus broad security and robustness improvements across agent, backend, and tooling.
Key changes:
- New fleet monitor API (endpoints for heatmap, comparison, alerts, thresholds, anomalies, forecast, search, exports, and Prometheus) and service skeleton.
- New DB models for ServerAlertThreshold and MetricAlert to support metric alerts.
- Agent discovery/registration hardening: HMAC-signed discovery requests, signature/timestamp validation, minimal discovery responses, HMAC-based unregister headers, and enforced command timeout cap in agent command handling.
- WebSocket and agent client TLS handling gated by SERVERKIT_INSECURE_TLS env var; added auth rate limiting on agent gateway.
- Docker-compose: parameterize agent image via AGENT_VERSION and avoid running as root by adding docker group access.
- Backend security & policy: tightened CSP script/style sources, request size limit, 2FA pending-token rejection on non-2FA endpoints, registration flow/guards, admin-only SSO admin routes via middleware, rate limits on sensitive endpoints, and logging for auth/2FA events.
- Database service hardening: identifier validation, avoid passing passwords on CLI (use env vars), safer subprocess usage, and docker exec handling improvements.
- CronService: command validation to prevent shell injection and run commands without shell=True; build_service and other subprocess usages updated similarly.
- Misc: .env.example notes clarified for encryption key generation, invitation token generation improved, agent registry timestamp window reduced, various logging and input validations added, frontend FleetMonitor page and styles stubbed in, and Vite/config/style updates.
Overall this commit implements fleet monitoring scaffolding and a set of security, validation, and operational improvements to make agent discovery, registration, command execution, and backend services safer and more robust.
Introduce team invitation support and a revamped email subsystem plus admin features. Adds Invitation model and API endpoints (create, list, revoke, resend, validate) and integrates invitation validation into user registration. Replaces old email account model with richer email models (EmailDomain, EmailAccount, EmailAlias, EmailForwardingRule, DNSProviderConfig) and updates models __init__. Refactors email API to manage domains, accounts, aliases, forwarding, DNS providers, spamassassin, Roundcube/Postfix services and queue/log endpoints. Adds several backend services (invitation, DNS provider, DKIM, Dovecot, Postfix, Roundcube, SpamAssassin, permission service) and a DB migration for permissions/invitations. Enhances admin API with permission management and activity dashboard endpoints, extends audit log actions, and adds a permission_required RBAC decorator. Includes frontend additions for settings/invitations UI and miscellaneous config/service updates and tests.
Introduces backend/app/paths.py to centralize all key directory paths, allowing overrides via environment variables for local development. Updates all backend services and APIs to use these centralized paths instead of hardcoded values. Adds dev path override examples to backend/.env.example and updates .gitignore to exclude dev-data. Also changes frontend dev server port to 5274 and updates related scripts and CORS settings for consistency.
- Create /app/instance directory in Dockerfile with proper permissions
- Update DATABASE_URL default to use absolute path (/app/instance/serverkit.db)
- Ensures the non-root appuser can write to the database location
- Fixes "unable to open database file" error on fresh installs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces backend API endpoints and service logic for managing firewalld and ufw, including status, rules, IP blocking, and installation. Updates CORS settings, improves Windows compatibility in file and FTP services, and adds required dependencies. Frontend changes include new Firewall and PHP pages, updated sidebar, and related styles.
Introduces new API endpoints and services for backups, monitoring, and Git deployment. Adds security middleware, account lockout on failed logins, and improves domain/SSL management. Updates Dockerfiles, deployment configs, and frontend to support new features and UI components.
Add backend and frontend foundations for ServerKit, including Flask API structure, SQLAlchemy models, service layers, and React app with authentication context and service hooks. Implement core API endpoints for authentication, application management, Docker, databases, and system operations. Update README with project overview, tech stack, and setup instructions. Add development roadmap and example environment configuration.