34 Commits
Author SHA1 Message Date
Juan Denis fbed88ea35 Stop serverkit update --help from updating
update, uninstall and cleanup-apps silently dropped any flag they did
not know, so 'serverkit update --help' ran a real update. --help now
prints usage and an unknown flag fails before anything runs.
2026-10-10 13:27:58 -04:00
Juan Denis 45bc3c70bd Guard first admin with a setup code, fix Git deploys
A fresh panel no longer lets whoever reaches it first become admin:
registering the first account needs a one-time code the installer
prints (`serverkit setup-code` repeats it). SERVERKIT_ADMIN_EMAIL and
SERVERKIT_ADMIN_PASSWORD create the admin unattended instead.

Git apps now deploy what users expect: a repository with a compose
file deploys every service it declares, "Deploy latest" builds the
branch's newest commit, and push webhooks rebuild the containers.
Also fixes branch switching on single-branch clones, uploads of a
lone file, compose v1 port preflight, and CLI commands that ignored
their flags.
2026-09-24 00:50:02 -04:00
Juan DenisandClaude Fable 5.1 5675f50c88 fix(cli): dispatch the connect verb through the wrapper
backend/cli.py gained `connect` (with status/doctor/disconnect) for the
ServerKit Cloud pairing but the `serverkit` wrapper never learned it, so
`serverkit connect` fell through to "unknown command" and the wrapper
dispatch census failed the Scripts CI suite. Add it to the help, the
dispatch case and bash completion; the passthrough test covers it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGmHp7mZ2wSeA6z8BXZVxh
2026-09-03 00:46:25 -04:00
Juan DenisandClaude Fable 5.1 c16c59644f fix(cli): doctor and start/stop read the frontend layout off nginx (#127)
`serverkit doctor` assumed the frontend is the `serverkit-frontend`
container. On a host install that container never exists: install.sh has
nginx serve frontend/dist from disk, and the container only lives under the
opt-in `legacy-frontend` compose profile. Doctor flagged a phantom issue on
every host install, and `--fix` "repaired" it with a bare `docker compose
up -d` in /opt/serverkit, which does not start that container at all: it
builds the whole all-in-one panel image, which would then collide with the
systemd backend on :5000. start/stop/restart/status/logs carried the same
assumption.

Add `frontend_mode`, which reads the layout off the serverkit vhost (a
`root .../frontend/dist` is static, a `proxy_pass` on / is the legacy
container, neither is unknown), and make every command key off it. Static
installs are checked for the bundle nginx actually serves; when it is
missing doctor names the command that restores it (`serverkit update`)
instead of promising an auto-fix. The legacy path targets the profile's
service (`docker compose --profile legacy-frontend up -d frontend`), never
the panel image.

Tests: static install passes with no compose call, missing bundle under
--fix hints at update and still never calls compose, frontend_mode
classifies all three layouts, and an awk guard fails the suite if a bare
compose call from $INSTALL_DIR comes back.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGmHp7mZ2wSeA6z8BXZVxh
2026-09-03 00:36:11 -04:00
Juan DenisandClaude Opus 5 e10ecc87d0 feat(cli): add serverkit disk to report and reclaim disk space
A panel host filled to 100% (0 bytes free) purely from routine
`serverkit update` runs, and recovering it meant hand-running du and
sqlite. `serverkit disk` measures every reclaimable item and offers them
for selection: numbers, "safe", or "all".

Upgrade snapshots are grouped by timestamp and offered individually with
age and size, since one update writes both a tree backup and a database
copy under one stamp -- half a snapshot is not a restore point. They can
be picked by number, by age (--older-than N, or "older-than N" in the
prompt), or left to the "all-but-newest" default.

Two ordering rules are enforced regardless of selection order:

* filesystem reclaimers run BEFORE the database VACUUM. VACUUM rewrites
  the database into a temp file beside it, so it needs free space equal
  to the database -- on a full disk it is the one step that cannot go
  first. It refuses with a clear message rather than failing halfway.
* `jobs` rows are deleted before `queue_messages`, and any message still
  referenced by a surviving job is kept, so jobs.queue_message_id never
  dangles.

in_flight messages and pending/failed jobs are never touched. /tmp is
only swept for entries matching mktemp naming, owned by the invoking
user, over 24h old AND holding an unpacked ServerKit tree. Docker prunes
dangling images and build cache only -- never tagged images or volumes.

Sizes are measured rather than estimated wherever measurement is
possible: docker reports its own reclaimed tally (shared layers make
dangling-image sizes overlap), and the journal and package caches report
before/after deltas -- apt-get clean empties the cache before a naive
count could see it, which would otherwise report 0 freed for real work.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 19:12:12 -04:00
Juan Denis 1b6cc38673 fix(cli): 'Updater not found' on serverkit update — check -f not -x
scripts/update.sh is tracked 0644 in git (invoked via bash), so the -x
guard in cmd_update rejected every update on a healthy install.
2026-07-22 22:39:02 -04:00
Juan DenisandClaude Fable 5 1face0702f fix(cli): wrapper delegates forward flags verbatim to cli.py
Live test on the dev box caught 'serverkit list-apps --json' printing
the table: cmd_list_apps' hand-rolled flag mapping dropped everything
but --all, and cmd_list_users/cmd_list_servers dropped all args. All
three now forward "$@" (with -a kept as the legacy --all alias), and
test_cli.sh T20 drives the real executed-mode dispatch through a fake
venv with a recording python stub so any wrapper verb that eats flags
fails the suite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:34:12 -04:00
Juan DenisandClaude Fable 5 ad73f0c581 fix(cli): wrapper parity with backend/cli.py + bash tab-completion
serverkit migrate-db forwarded the wrapper's own name to cli.py, which
only defines db-migrate — the command has failed with 'No such command'
since the rename. Fix the forward and stop the drift class entirely:

- cmd_panel_cli forwards Click-only verbs verbatim (manifest, services,
  apps, repair, login-url, support-bundle, db-migrate/status/history;
  panel-status/panel-doctor where a native bash name collides)
- serverkit completion prints a bash completion script; install.sh and
  update.sh drop it into /etc/bash_completion.d (best-effort), the
  uninstall lib removes it
- test_cli.sh T17-T19: migrate-db forwarding, dispatch reachability,
  and a two-way parity guard (cli.py verbs <-> dispatch <-> completion);
  test_update.sh T29 covers refresh_bash_completion

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 01:23:00 -04:00
Juan DenisandClaude Fable 5 62300b4299 fix(cli): guard start/restart/logs/add-site, loud --branch error, RHEL nginx layout (L4-L7,L9,L12)
- update --branch without a value errors loudly instead of dying
  silently on shift (L5)
- cmd_start/cmd_restart mirror cmd_stop's systemctl/docker guards (L6)
- cmd_logs degrades past a dead/missing journalctl to docker logs (L7)
- cmd_add_site/remove_site/list_sites detect Debian vs conf.d nginx
  layout; reloads are guarded with a manual-reload hint (L9)
- uninstall on a remnants-only box prints exact recovery commands (L4)
- portable port extraction (no grep -oP), read-at-EOF defaults,
  compare_versions rejects unparsable as update-available, doctor
  exits nonzero on issues (L12); BASH_SOURCE guard for testability
- new scripts/test/test_cli.sh (22 passed)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 18:00:15 -04:00
Juan DenisandClaude Opus 4.8 754bfb4a67 feat(install): Phase 1 hardening — firewall automation, py3.11/3.12, unified uninstall
Critical install/update/uninstall hotfixes from the hardening plan
(docs/plans/INSTALLER_UPDATER_UNINSTALLER_HARDENING_PLAN.md §4):

- Firewall automation (G1): new sourceable scripts/lib/firewall.sh detects
  firewalld/ufw/nftables/iptables and opens 80/443; install.sh runs
  configure_firewall, update.sh re-ensures it idempotently. Exactly what we
  open is recorded in /etc/serverkit/install-state.json (scripts/lib/state.sh)
  so uninstall undoes only our rules. Fixes the #1 "installed but unreachable"
  failure on fresh RHEL-family boxes.

- Accept Python 3.11 OR 3.12 (G2): locate_python now iterates
  python3.12/3.11/3 and provision_python installs the distro package
  (python3.11 on Debian 12, 3.12 on Ubuntu/Fedora, 3.11/3.12 on RHEL) before
  ever falling back to a source compile.

- Use $PYTHON_BIN for secret generation instead of a bare python3.

- Distro-first Node 20 (replacing unconditional NodeSource): install the
  distro nodejs+npm, fall back to NodeSource only when it's missing or < 18,
  and validate node>=18 before continuing.

- Unify uninstall (G4): new scripts/lib/uninstall.sh is the single canonical
  teardown routine shared by uninstall.sh and `serverkit uninstall` (they had
  drifted — one ran `down -v`, one didn't). Default preserves user data
  (volumes kept, DB snapshotted to backups); --purge/--delete-volumes removes
  volumes+DB+data dirs; --keep-data preserves /etc + /var/lib + backups;
  --yes/--dry-run added; honors SERVERKIT_DIR. Removes the apt lock-wait
  drop-in on uninstall.

Tests: new scripts/test/test_install.sh (11 cases, source-able install.sh)
covers python/node detection, firewall dry-run + state, and the uninstall
data-handling matrix. Existing test_update.sh still green. shellcheck clean
(error + warning) on all new/changed shell.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 00:24:39 -04:00
Juan Denis 3f37994f18 feat(installer): atomic blue/green updates, pre-flight checks, offline support, pre-built releases
- Rewrite scripts/update.sh with pre-flight validator (disk, memory, Python,
  deps, network, health) and automatic rollback on failure.
- Implement atomic blue/green install layout (/opt/serverkit-a|b + symlink).
- Add explicit database migration step (flask db upgrade) before switching slots.
- Add --dry-run, --force, --branch, --release flags to update.sh.
- Add SERVERKIT_OFFLINE_TARBALL and SERVERKIT_MIRROR_URL support.
- Verify release tarball SHA-256 checksums on download.
- Ship pre-built frontend/dist and relocatable venv in release tarballs.
- Make serverkit update delegate fully to scripts/update.sh; remove inline
  _update_source fallback.
- Harden install.sh for blue/green, checksums, offline, and pre-built venv.
- Update uninstall to remove both blue/green slots and backups.
- Update docs/INSTALLATION.md and README.md with new options.
2026-06-23 11:02:26 -04:00
Juan Denis d951a20264 fix(install/update/uninstall): robust lifecycle + masthead + schedule_card guard
- update.sh: default to pulling latest main source; clone release installs to git
- update.sh: auto-rollback on failed release swap, tarball layout detection,
  backend/instance mkdir, executable-bit restore, frontend dist build,
  force-recreate frontend container after dist rebuild
- install.sh: normalize serverkit/ vs opt/serverkit/ tarball layouts
- serverkit/uninstall.sh: install-style masthead + tagline
- ScheduleCard.jsx: guard against undefined policy to prevent dashboard crash
2026-06-22 23:24:24 -04:00
Juan Denis 2b7a98c348 feat: canonical domain + encryption key bootstrap
- Auto-generate SERVERKIT_ENCRYPTION_KEY in production when missing.
- Detect canonical domain from Host/X-Forwarded-Host; persist via SystemSettings.
- Expand CORS origins dynamically to include the canonical domain.
- Add SystemTab UI to view/save detected panel domain and HTTPS preference.
- Install script writes key, prompts for PANEL_DOMAIN, and sets nginx IP→domain redirect.
- Add backend tests for key bootstrap and domain detection helpers.
2026-06-19 01:34:02 -04:00
Juan Denis f9c31aec32 feat(installer): guided install/update flow with health-checked rollback
- install.sh: staged installer with pre-flight checks (disk/memory/root),
  apt/dnf lock handling, low-RAM safe mode + swap, source-or-release install
  modes, generated secrets/.env, self-signed cert bootstrap, nginx + systemd
  wiring, a post-install health probe with automatic rollback, and optional
  Let's Encrypt issuance for the panel domain.
- scripts/update.sh: in-place updater with release self-refresh, pre-update
  database + tree backups, release/source paths, health-checked rollback,
  and backup pruning.
- scripts/build-release.sh: builds a portable release tarball (pre-built
  venv + frontend) at the repo root.
- serverkit CLI: 'update' delegates to scripts/update.sh and accepts
  --release [vX.Y.Z].
- Harden the serverkit-agent unit (kernel/namespace protections, MemoryMax,
  LimitNOFILE) and ignore release tarball artifacts.
2026-06-19 01:33:17 -04:00
Juan Denis cc1151d0ce Add deployment jobs and remote deployment runner
Introduce a deployment jobs system to support cross-server template installations and remote execution. Adds DeploymentJob and DeploymentJobLog models, DeploymentJobService for job lifecycle, and DeploymentPlanRunner to execute plans locally or via agents. TemplateService gains build_install_plan and related helpers to produce executable plans; Template installs can run async (202) or synchronously. Backend API/CLI updated: new deployment-jobs endpoints, apps API uses RemoteDockerService for remote compose actions, and CLI commands (deploy-template, deployment-status, list-servers) were added. Agent and config changes: file access validation with allowed_paths, file write create_dirs option, default allowed paths, and install script/systemd read-write paths updated to permit /var/lib/serverkit and /var/serverkit. Migration file for deployment_jobs schema included.
2026-04-29 00:39:16 -04:00
Juan Denis e0492f54f0 Move nginx private URLs to location snippets
Generate private URL configs as location-only snippets in /etc/nginx/serverkit-locations instead of full server blocks. nginx_service.py: write location snippets (.conf) to LOCATIONS_DIR, ensure the locations directory, remove legacy separate server blocks, and add get_location_config to read these snippets (used for private URLs, Gitea, WordPress). install.sh & serverkit: only remove conflicting catch-all (server_name _) configs that are not ServerKit-managed (skip serverkit.conf and serverkit-*), strengthen the server_name regex, and create the serverkit-locations dir. cmd_doctor: add docker presence checks and avoid frontend checks when docker is missing; require root in --fix mode. Misc cleanup and minor refactors around enabling/disabling configs and reload handling.
2026-03-28 13:47:43 -04:00
Juan Denis 39ac49609e Use nginx location snippets and add doctor
Switch Gitea/WordPress to location-only snippets included into serverkit.conf and introduce /etc/nginx/serverkit-locations. NginxService now writes snippets to LOCATIONS_DIR, ensures the directory exists and removes legacy full-server configs to avoid server_name _ conflicts; validation blocks use of the reserved catch-all name. install.sh and the update path create the locations dir and remove any conflicting catch-all site configs. serverkit.conf proxy port updated (8080 -> 3847) and now includes the snippets directory. Add a new serverkit doctor command (with --fix) and help entries to run diagnostics and auto-fix common issues (nginx, docker, service health, ports, disk, DB, etc.).
2026-03-28 12:46:33 -04:00
Juan Denis fc02f40636 Add tracking for install, update, and uninstall events
Added calls to serverkit.ai to track successful installation, update, and uninstall events with the current version. This helps monitor usage and improve support.
2026-01-28 22:31:46 -05:00
Juan Denis df1cc3b117 Enhance uninstall script with detailed cleanup steps
Expanded the uninstall process to explicitly list all components and directories that will be removed, including nginx configs and ServerKit-specific data. Added informational messages and ensured nginx is reloaded if necessary. Clarified that system packages are not removed automatically.
2026-01-27 21:54:14 -05:00
Juan Denis 06d63cbc52 Add standalone WordPress and SSL management UI
Implements backend endpoints and service logic for managing standalone WordPress via Docker, including install, uninstall, start, stop, and restart. Adds Nginx integration for WordPress at /wordpress. Introduces a new frontend page for SSL certificate management with Certbot install, obtain, renew, and revoke actions. Updates the WordPress frontend page to support one-click install, status, and lifecycle management. Updates documentation and install instructions for improved clarity.
2026-01-25 22:48:12 -05:00
Juan DenisandClaude Opus 4.5 bb2159f4e6 feat: Add branch switching support to serverkit CLI
- Add 'serverkit update --branch <name>' to switch branches
- Add 'serverkit branch' command to show current branch
- Skip version check for non-main branches (dev mode)
- Show commit hash and branch in update output
- Warn users when running on non-main branch

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 19:31:15 -05:00
Juan Denis 679ccf9f62 Enhance app cleanup and listing with Docker resource management
Expanded the cleanup and factory reset commands to remove orphaned Docker containers, networks, and volumes while preserving ServerKit infrastructure. Improved the list-apps command to optionally display all Docker containers with a new --all flag, and updated documentation and CLI help to reflect these changes.
2026-01-19 17:16:25 -05:00
Juan Denis 81179411d6 Add app cleanup and database migration commands
Introduces new commands to manage applications and perform database migrations: `cleanup-apps`, `factory-reset`, and `migrate-db`. Updates documentation and help output to reflect these additions, and refactors `list-apps` to use the CLI for consistency.
2026-01-19 17:07:52 -05:00
Juan DenisandClaude Opus 4.5 2c4976e4f5 feat: Add Docker cleanup to install/update and --force flag
- Add docker network prune and docker system prune before builds
- Use --no-cache for docker compose build to ensure fresh builds
- Add --force / -f flag to skip version check during update
- Helps prevent Docker networking issues

Usage: sudo serverkit update --force

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 23:38:13 -05:00
Juan DenisandClaude Opus 4.5 49d6ef27d4 fix: Version comparison not exiting early due to set -e
The compare_versions function returns non-zero values to indicate
version differences, but 'set -e' was causing bash to exit.
Now temporarily disabling exit-on-error during version comparison.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 23:07:11 -05:00
Juan DenisandClaude Opus 4.5 8bccfcdcf8 feat: Add automatic versioning system
- Add VERSION file (starting at 1.0.0)
- Add GitHub Actions workflow to auto-bump version on push
  - patch: default for all commits
  - minor: commits starting with "feat:" or "feature:"
  - major: commits starting with "BREAKING:" or "major:"
- Add CLI commands: version, check-update
- Update 'serverkit update' to show semantic versions
- Compare local vs remote version before updating

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 23:00:10 -05:00
Juan DenisandClaude Opus 4.5 b43bae9a49 Fix: Copy app templates to /etc/serverkit/templates during install
- Install script now copies bundled YAML templates to system directory
- Update command syncs templates on each update
- Creates /var/serverkit/apps directory for installed apps

Fixes 'No templates found' in Templates page.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 22:41:10 -05:00
Juan DenisandClaude Opus 4.5 736deb0832 Fix: Prevent getcwd errors by ensuring valid working directory
- install.sh now starts with cd /tmp to ensure valid directory
- uninstall command moves to /tmp before deleting install dir
- Shows reinstall command after uninstall

Prevents 'cannot access parent directories' errors when running
install from a deleted directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 22:33:40 -05:00
Juan DenisandClaude Opus 4.5 2c8f8f4b64 Fix: Restore executable permissions after git update
The update command now restores chmod +x on serverkit and scripts
after git reset --hard to prevent permission denied errors.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 22:26:45 -05:00
Juan DenisandClaude Opus 4.5 cab18a32b7 Consolidate templates into backend/templates marketplace
- Removed duplicate root templates/ folder
- Added PHP, Python, Node.js templates to marketplace (YAML format)
- Templates now installable via web UI Templates page
- CLI create-app now points users to web UI
- All 63 templates in one place: backend/templates/

New templates:
- php-app: Custom PHP 8.0-8.3 with Apache
- python-app: Custom Python 3.9-3.12 (Flask/FastAPI/Django)
- node-app: Custom Node.js 18-21 (Express/Next.js)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 22:23:50 -05:00
Juan DenisandClaude Opus 4.5 e65c680ba2 Add Docker-based app templates for PHP, Python, and Node.js
No need to install PHP/Python/Node on the host - each app runs
in its own isolated Docker container with the exact version needed.

Templates:
- PHP: nginx + php-fpm (8.0, 8.1, 8.2, 8.3)
- Python: Flask/FastAPI/Django (3.9-3.12)
- Node.js: Express/Next.js (18, 20, 21)

New CLI commands:
- create-app <type> <name> [port] - Create new app from template
- list-apps - List all deployed apps
- start-app <name> - Start an app
- stop-app <name> - Stop an app
- app-logs <name> - View app logs

Usage:
  sudo serverkit create-app php myblog
  sudo serverkit create-app python myapi 8200
  sudo serverkit add-site myblog.domain.com 8100

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 22:17:46 -05:00
Juan DenisandClaude Opus 4.5 eebb37fd5b Add multi-site support with host nginx reverse proxy
- Host nginx routes domains to different apps
- ServerKit frontend moved to port 8080 (internal)
- New CLI commands: setup-proxy, add-site, list-sites, remove-site
- Site config templates for easy domain setup
- Install script now sets up nginx proxy automatically

Usage:
  sudo serverkit add-site test.example.com 3000
  sudo serverkit list-sites
  sudo serverkit remove-site test.example.com

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 22:04:26 -05:00
Juan Denis c95d01b2fb Refactor to run backend on host, frontend in Docker
Removed docker-compose.prod.yml and updated docker-compose.yml to only run the frontend in Docker, with the backend now running as a systemd service on the host. Updated nginx and frontend nginx.conf to proxy API requests to the backend on the host. Added serverkit-backend.service for systemd management of the backend. Refactored install.sh and serverkit CLI to support the new architecture, including improved installation, update, and management commands.
2026-01-18 21:15:31 -05:00
Juan Denis c1d60f112f Add ServerKit CLI, install script, and deployment improvements
Introduces a comprehensive Bash CLI tool (`serverkit`) for managing ServerKit services, users, and database operations. Adds a quick-install script (`install.sh`) for Ubuntu, a sample environment file (`.env.example`), and a Python CLI backend (`backend/cli.py`) for administrative tasks. Updates Docker Compose for production readiness, enhances deployment documentation, and adds Click to backend requirements. Also updates references to the correct GitHub repository.
2026-01-17 12:13:22 -05:00