10 Commits

Author SHA1 Message Date
myron 321a88fa28 fix: copy VERSION to web root on every deploy
deploy-runner.sh was rsyncing panel/public/ but VERSION lives at repo
root — web root /srv/novacpx/public/VERSION was perpetually stale.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 14:37:40 +00:00
myron 4d7c35076b Fix 10 code review findings: security, correctness, and SQLite compat
- system.php: fix null dereference on fetchOne (TypeError on null['value'])
- system.php: validate update_channel to ['stable','beta'] to prevent shell injection
- system.php: escapeshellarg remoteBranch in git log/show calls (was RCE vector)
- system.php: fix backup path — rsync contents, not directory, so restore is symmetric
- system.php: syntax check only changed files (git diff) not all 300+ panel files
- system.php: copy VERSION to $webRoot/VERSION not $webRoot/../VERSION (wrong path)
- system.php: fix 3× ON DUPLICATE KEY UPDATE → SQLite ON CONFLICT syntax
- deploy-runner.sh: hoist DB_PATH/CHANNEL above while loop
- deploy-runner.sh: sanitize NEW_VERSION and commit hashes before SQL interpolation
- deploy-runner.sh: parse queued branch (4th field) from webhook queue entry
- webhook.php: remove dead $branch config variable
- webhook.php: include pushed branch in queue entry to eliminate TOCTOU race

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 03:06:14 +00:00
myron 14aa6e8b4d Fix column name: commit_hash → git_commit in novacpx_version INSERT
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:55:43 +00:00
myron 9cabe8af5e Wire update channel (stable/beta) into settings, check, deploy, and version tracking
- Settings page now loads current values from DB and saves via save-option API
- check-novacpx-update reads update_channel setting, checks origin/main or origin/beta
- apply-novacpx-update pulls from channel branch, fixes backup dir (/tmp), fixes SQLite migration syntax, records new version in novacpx_version table + settings.panel_version
- deploy-runner.sh reads update_channel from DB, pulls correct branch, records version after deploy
- webhook.php accepts pushes to both main and beta branches
- Updates page shows channel badge and latest remote version

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:44:46 +00:00
myron 5aaeaa9a35 Fix deploy-runner: SQLite migration tracking, re-create webhook symlink after rsync
Switches migration tracking from MySQL to SQLite (panel.db), reads DB path
from config.ini with fallback to /var/lib/novacpx/panel.db.  Re-creates the
webhook symlink after each rsync deploy so it survives --delete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 18:09:02 +00:00
myron bcd3b65520 Run panel on dedicated novacpx-web Nginx service; fix auth/transaction methods
- deploy/nginx-panel.conf: standalone Nginx config for ports 8880-8883
- deploy/novacpx-web.service: systemd unit, survives apache2/nginx stop
- server_setup.php: fix Auth::requireRole() -> require('admin')
- DB.php: add beginTransaction()/commit()/rollback() methods
2026-06-09 16:00:32 +00:00
myron d587ad4ebd Fix web server switch — panel always stays on Apache
- novacpx-webserver-switch: new helper script that manages ports 80/443
  only; panel ports 8880-8883 are never touched
- system.php: save-option web_server now calls the helper script instead
  of stopping all web servers (which killed the panel)
- admin.js: server options shows live Apache/Nginx status badges and notes
  that the panel always runs on Apache
2026-06-08 16:36:49 +00:00
myron bfa2cfc3f8 fix: CyberMail from field format + deploy runner syncs api/ and lib/
- Notifier.php + test-notify: use plain email address in 'from' field
  (CyberMail rejects "Name <email>" format)
- deploy-runner.sh: rsync panel/api/ and panel/lib/ to web root after
  panel/public/ sync; also syncs panel/bin/ to /opt/novacpx/bin/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 04:40:16 +00:00
myron 62707d62ce Fail2Ban whitelist management + auth failure logging
- firewall.php: auto-detect server IPs (loopback, all interface IPs,
  private /24 subnets) for Fail2Ban ignoreip; f2b-ignoreip-list/add/
  remove/reset actions; write to jail.local directly (www-data owns it);
  f2b_set_ignoreip() reloads fail2ban after every change
- auth.php: log failed logins to /var/log/novacpx/access.log in format
  fail2ban filters expect — "FAILED LOGIN from <IP> [portal]"
- deploy/fail2ban/: filter.d conf files for all 4 NovaCPX jails
- install.sh: auto-detect local IPs → ignoreip in jail.local; install
  filter files; create access.log (www-data:www-data 664)
- admin.js: Fail2Ban Whitelist section in firewall page — chip list with
  add/remove/reset; loopback shown with lock icon and non-removable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 16:10:05 +00:00
myron e94dc719c8 feat: feature registry, auto-deploy, IP management, Docker support
Feature Manager (70+ features across 20 categories):
- Web servers: Apache2, nginx, OpenLiteSpeed, Varnish
- PHP: 7.4/8.1/8.2/8.3 multi-version, Composer
- Databases: MySQL 8, MariaDB, PostgreSQL, Redis, Memcached, phpMyAdmin, phpPgAdmin
- Email: Postfix, Dovecot, Roundcube, RainLoop, SpamAssassin, Rspamd, DKIM
- DNS: BIND9, PowerDNS
- FTP: ProFTPD, vsftpd, Pure-FTPd
- SSL: Certbot/Let's Encrypt, acme.sh
- Security: Fail2Ban, ModSecurity WAF, ImunifyAV, ClamAV, UFW, CrowdSec
- Containers: Docker Engine, Docker Compose, Portainer CE, per-account Docker hosting
- IP Management: Shared IPs (SNI), Dedicated IPs, IPv6
- Monitoring: Netdata, AWStats, GoAccess, Grafana+Prometheus
- Backup: BorgBackup, rclone (S3/B2/GCS), Duplicati
- CDN: Cloudflare API, PageSpeed Module
- Dev: Gitea, Phusion Passenger, JupyterHub
- One-click apps: WordPress+WP-CLI, auto-installer (50+ apps)
- Billing: WHMCS bridge, BoxBilling
- Reseller: White label, custom nameservers
- Notifications: Email, Slack, Telegram
- Compliance: Auditd, OSSEC HIDS

Auto-deploy pipeline (deploy/):
- webhook.php: HMAC-verified GitHub push webhook
- deploy-runner.sh: PHP syntax validation → git pull → rsync → DB migrations → PHP-FPM reload
- setup-deploy.sh: one-shot setup script, outputs GitHub webhook config
- Runs every minute via cron; locked to prevent concurrent deploys

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 05:11:36 +00:00