curl | bash pipes stdin so read gets EOF and returns non-zero, which
set -euo pipefail treats as an error and aborts immediately. Replaced
the interactive prompt with a sleep 5 countdown — works whether the
script is piped or run directly.
Bumps version to 0.6.3.
set -euo pipefail causes the script to exit when read gets EOF from
the curl pipe instead of an interactive terminal. Fix by appending
'< /dev/tty || CONFIRM=Y' so the prompt reads from the actual terminal
regardless of how the script was invoked.
Adds CLAUDE.md which Claude Code reads automatically before every
session. Covers version bumping, changelog format, commit conventions,
file size limits, section/page architecture, and API standards.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Frontend:
- Extract Layout.tsx (801 lines) into navData.ts, Sidebar.tsx, and thin Layout.tsx
- Split Settings.tsx into settings/FormControls, ContactTab, BasicTab, NameserversSection
- Add server-configuration/ section with index card grid and one file per tool (13 tools)
- Add shared SectionCard and ComingSoon components
- Nav category headers with a section index link (optional `to` field on NavCategory)
- /settings redirects to /server-configuration/basic-setup
Backend:
- Split accounts.ts (671 lines) into accounts/list, create, modify, status sub-plugins
- Add GET /api/nixserver/system/network-interfaces for ETHDEV dropdown
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
package-lock.json generated on Windows includes win32 rollup binary but
not linux-x64-gnu, breaking the frontend build on the server.
- Add package-lock.json to .gitignore and remove it from git tracking
- update.sh: rm -rf node_modules + package-lock.json before npm install
so the server always generates a platform-correct lock file from scratch
- update.sh: remove --silent from build steps so errors are visible
- .gitignore: fix stale whm/cpanel dist paths → nixserver/nixclient
npm install modifies package-lock.json on the server, causing
'git pull --ff-only' to abort with 'your local changes would be
overwritten'. Add 'git checkout -- package-lock.json' before the pull
so the generated lock file never blocks updates.
Login page had 'NixServer v0.3.2 · Port 2087' hardcoded and subtitle
said 'Web Host Manager'. Now fetches version from GET /api/health on
mount (no auth needed) and shows it dynamically. Changed subtitle to
'Admin Panel'.
The old package-lock.json still referenced @nixpanel/whm as a workspace.
After the package rename in v0.4.6, npm install failed to resolve the
workspace correctly, causing the nixserver frontend build to fail and
breaking login. Deleted and regenerated package-lock.json cleanly.
The refresh/retry button called fetchVersion() without clearing
versionInfo first, so the old value stayed displayed with no feedback.
On manual refresh it now immediately sets versionInfo to null (shows
spinner) then fetches with ?_t=Date.now() to bypass any browser cache
of the API response.
Bump version to 0.4.5 to include all fixes since 0.4.4 (day/night
toggle, uptime/kill allowlist, auto-retry on version error).
Add ThemeContext (dark/light, persisted to localStorage, applied as
data-theme on <html>). Theme toggle is a sun/moon flip switch at the
right end of the dashboard info bar.
CSS overrides in index.css target every hardcoded Tailwind arbitrary
colour class used across all pages via [data-theme="light"] selectors,
so the entire panel switches without touching individual page files.
Light palette: page #f0f4f8, cards/sidebar #ffffff, hover #f1f5f9,
borders #e2e8f0, text #0f172a. Chart tooltip is made theme-aware via
inline-style interpolation since Tailwind CSS overrides cannot reach
Recharts inline styles.
Layout.tsx: when versionError is true, automatically retry fetchVersion
after 5 s. This handles the case where the initial fetch runs during
the service-restart window after an upgrade (server not yet up), which
caused the sidebar footer to permanently show 'Version unavailable'
even though the server came back online shortly after.
exec.ts: add 'uptime' and 'kill' to ALLOWED_COMMANDS. 'uptime' was
missing, causing exec('uptime', ['-p']) in GET /api/nixserver/system/info
to throw 'Command not allowed', which rejected the entire Promise.all
and returned 500 — leaving Hostname and OS as '...' on the dashboard.
Plain axios was called without the Authorization header, so the
requireAdmin middleware rejected every request with 401. The catch
block set versionError but the error state was also not yet deployed,
leaving the spinner stuck on 'Checking version…' forever.
Switch both axios.get('/api/nixserver/system/version') and
axios.post('/api/nixserver/system/upgrade') to the api client from
../api/client, which automatically attaches Bearer token from
localStorage on every request.
Adds a compact info strip at the top of the NixPanel dashboard showing
Username, Hostname, OS, NixPanel Version, Load Averages (live via
WebSocket), and Server Monitoring alert count. Alert count is derived
from GET /api/nixserver/services — green "All Clear" when all services
are running, amber "N Alerts" for any stopped/failed service.
Also fixes the version footer error state in Layout.tsx (versionError
→ "Version unavailable" fallback with retry button) so the spinner no
longer hangs indefinitely when the version API is unreachable.
Add version badge to sidebar footer showing installed vs latest version,
fetched from /api/nixserver/system/version. Badge shows green when up to
date or amber with target version when an update is available.
Upgrade button triggers POST /api/nixserver/system/upgrade which spawns
scripts/update.sh detached (git pull + npm install + prisma migrate +
build + restart). Response is returned before the service restarts so
the client receives confirmation. Panel comes back online in ~60 s.
Replace the flat 14-item nav with a full category sidebar matching
the WHM layout. 29 collapsible categories, ~210 menu items, live
search that filters across all categories and auto-expands results,
active route auto-expands the matching category, sidebar toggle
hides/shows the full panel.
Without proxy_http, ProxyPass to HTTP backends silently fails and Apache
returns 500 for all API requests. Without proxy_wstunnel, the WebSocket
RewriteRule for live stats cannot proxy ws:// connections.
Apache (www-data) couldn't traverse /opt/nixpanel/nixserver because the
directories lacked execute permission for other. Add an explicit chmod
step after the build to ensure all dist directories are 755 and files
are 644 so Apache can serve the static assets.
The 'Creating directory structure' step runs mkdir -p on INSTALL_DIR
before the clone step, so git clone fails if the directory is non-empty.
Clone to a temp directory and copy contents into place to preserve any
existing data/ and logs/ subdirectories.
On Ubuntu 24.04 the SpamAssassin service unit is 'spamd', not 'spamassassin'.
The old 'systemctl enable spamassassin' call exited with an error because the
unit file does not exist, killing the install due to set -euo pipefail.
Also moved the systemd-resolved stub listener disable to a dedicated step that
runs before the package installation step. Previously it ran inside the PowerDNS
config block — after apt had already tried (and failed) to restart pdns during
post-install because systemd-resolved was still holding port 53.
- Add /api/nixclient/ssl (GET) — returns certs for authenticated user only
- Add /api/nixclient/ssl/:id/renew (POST) — validates cert belongs to user
- Register sslRoutes in nixclient index.ts
- nixclient SSL.tsx was calling /nixserver/ssl (requireAdminOrReseller)
which would always 401 for regular users — fixed to /nixclient/ssl
Service stack (backend):
- webserver.ts rewritten: apache2/php-fpm routes replacing nginx; per-account
Apache log endpoint; PHP-FPM reload per version; apache2ctl configtest/reload
- accounts.ts: added PUT /:id/shell to toggle /bin/bash vs /usr/sbin/nologin,
runs usermod -s and writes audit log
New UI features (nixserver):
- ShellAccess page: grant/revoke SSH access per account via AccountPicker
- ApacheLogs page: live log viewer (access/error) per account; replaces stub
- NginxLogs: re-exports ApacheLogs (NixPanel uses Apache, not NGINX)
- WebServer page: shows apache2, php8.2-fpm, php8.3-fpm status with reload
buttons; config test; Apache log viewer
Bug fixes:
- Accounts.tsx: Lucide icon size prop type widened (string|number); removed
unused Users import; dropped duplicate NGINX log card
- Removed soon badge from ShellAccess and ApacheLogs entries
Project:
- CHANGELOG.md created with full history from 0.2.x through 0.4.0
- All packages bumped from 0.3.2 to 0.4.0
StepContent was a component defined inside Setup, so every state
change recreated it as a new component type, causing React to
unmount/remount it and snap focus back to autoFocus. Replaced with
inline conditional JSX blocks.
After first login, admins are redirected to a 4-step setup wizard:
1. Server hostname (FQDN)
2. Primary and secondary nameservers
3. Admin email and optional password change
4. Review and confirm
Setup state is persisted in the settings table (setup_complete=true).
Once complete, the redirect never triggers again. Settings are saved
to the DB and hostname is applied via hostnamectl.
Nginx listens publicly on 2087/2083 and reverse-proxies to 127.0.0.1:4000.
Previously both Nginx and Node.js were trying to bind port 2087 causing the
nixpanel service to crash-loop. HOST changed to 127.0.0.1 so the API is
not directly reachable from outside.
Bumps version to 0.3.1.
- Fix version banner showing 0.1.0 instead of 0.2.0
- Fix admin password line printing "<auto-generated>true" when
GENERATED_PASS=true due to broken parameter expansion — replace
with explicit if/else