IMPORTANT: This guide is for setting up the CloudNet Panel after Phase 1 security improvements.
This version includes breaking changes that improve security:
- JWT_SECRET is now REQUIRED - Server will not start without it
- CORS is now whitelisted - Only specified origins can access the API
- Admin user is no longer hardcoded - Must be created via wizard
- WebSocket authentication changed - Token must be in protocol header
- Node.js 18+
- npm 8+
- SQLite 3
- (Optional) CloudNet server running
# Root dependencies
npm install
# Server dependencies
cd server && npm install
# Client dependencies
cd ../client && npm installCRITICAL: Generate a secure JWT secret (required for server to start):
# From project root
npm run generate-secret -- --saveThis will:
- Generate a cryptographically secure 128-character secret
- Save it to
server/.envautomatically - Display the secret for manual copying if needed
Alternative (manual):
npm run generate-secret
# Copy the output and add to server/.env:
# JWT_SECRET=<generated-secret-here>Edit server/.env and configure:
# Security (REQUIRED)
JWT_SECRET=<your-generated-secret>
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
# JWT Token Expiry (optional, defaults shown)
JWT_ACCESS_EXPIRY=1h
JWT_REFRESH_EXPIRY=7d
# Server (optional)
PORT=5000
NODE_ENV=development
# CloudNet API (if you have CloudNet server)
CLOUDNET_API_ENABLED=true
CLOUDNET_API_URL=http://127.0.0.1:2812/api/v3
CLOUDNET_API_USERNAME=administrator
CLOUDNET_API_PASSWORD=administratorNODE_ENV=production
ALLOWED_ORIGINS=https://yourdomain.com
JWT_ACCESS_EXPIRY=1hRun the interactive wizard to create an administrator account:
cd server
npm run create-adminFollow the prompts:
- Username: Min 3 chars, alphanumeric + hyphens/underscores
- Email: Valid email format
- Password: Min 8 chars, must include uppercase, lowercase, and number
- Confirm Password: Must match
Example:
Admin Username (min 3 chars, alphanumeric): admin
Admin Email: admin@localhost.local
Admin Password (min 8 chars, must include: uppercase, lowercase, number): Admin123!
Confirm Password: Admin123!
β
Admin user created successfully!
Development mode (separate servers):
# Terminal 1 - Backend
cd server
npm run dev
# Terminal 2 - Frontend
cd client
npm run devOr use concurrently (both in one terminal):
# From project root
npm run devProduction mode:
# Build frontend
cd client
npm run build
# Start server (serves built frontend)
cd ../server
npm startYou should see:
π Running startup validation...
β
All validation checks passed!
π CloudNet Panel server running on port 5000
Environment: development
CloudNet API: ENABLED
CloudNet URL: http://127.0.0.1:2812/api/v3
β
Server ready at http://localhost:5000
# Login with your admin credentials
curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "Admin123!"
}'Expected response:
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"username": "admin",
"email": "admin@localhost.local",
"role": "Administrators"
}
}# Use the token from login response
curl -X GET http://localhost:5000/api/auth/me \
-H "Authorization: Bearer <your-token-here>"Open browser: http://localhost:3000 (or http://localhost:5173 for Vite dev server)
Login with your admin credentials.
Access Token:
- Expires in 1 hour (configurable via
JWT_ACCESS_EXPIRY) - Used for API authentication
- Include in
Authorization: Bearer <token>header
Refresh Token:
- Expires in 7 days (configurable via
JWT_REFRESH_EXPIRY) - Used to get new access token when expired
- Send to
/api/auth/refreshendpoint
Token Refresh Example:
curl -X POST http://localhost:5000/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refreshToken": "<your-refresh-token>"}'New format (secure):
JavaScript:
const token = 'your-jwt-token';
const ws = new WebSocket('ws://localhost:5000', [
`authorization.bearer.${token}`
]);React:
const connectWebSocket = (token) => {
const ws = new WebSocket(
'ws://localhost:5000',
[`authorization.bearer.${token}`]
);
ws.onopen = () => console.log('Connected');
ws.onerror = (err) => console.error('WS Error:', err);
ws.onclose = (event) => console.log('Closed:', event.code);
return ws;
};β Old format (insecure, no longer works):
// DON'T USE THIS - Token visible in logs!
const ws = new WebSocket(`ws://localhost:5000?token=${token}`);Error: JWT_SECRET is required
- Solution: Run
npm run generate-secret -- --save
Error: Port 5000 is already in use
- Solution: Change
PORTinserver/.envor kill process using port 5000
Error: Database not accessible
- Solution: Ensure
server/databasedirectory exists and is writable
Error: Invalid credentials
- Solution: Verify username/password, recreate admin:
npm run create-admin
Error: Too many authentication attempts
- Solution: Wait 15 minutes (rate limiting), or restart server to reset
Error: Access-Control-Allow-Origin in browser console
- Solution: Add your frontend URL to
ALLOWED_ORIGINSinserver/.env - Example:
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
Error: Authentication failed on WebSocket
- Solution: Update client code to use new protocol header format (see above)
Error: Policy Violation (1008)
- Solution: Token is invalid or expired, get new token via login
Endpoint: GET /api/health
curl http://localhost:5000/api/healthResponse:
{
"status": "ok",
"timestamp": "2026-02-02T18:00:00.000Z",
"version": "1.0.0"
}Authentication endpoints:
- Limit: 5 attempts per 15 minutes
- Applies to:
/api/auth/login
General endpoints:
- Limit: 100 requests per minute
- Applies to: All other endpoints
When limited:
- Status: 429 (Too Many Requests)
- Response:
{ "success": false, "error": { "code": "AUTH_RATE_LIMIT_EXCEEDED", "message": "Too many authentication attempts. Please try again in 15 minutes." } }
-
Read Documentation:
PROGRESS.md- Implementation progressSESSION_SUMMARY.md- What was changed.claude/00_LIRE_DABORD.md- Original audit
-
Update Frontend:
- WebSocket authentication (use protocol header)
- JWT refresh token handling
- CORS configuration
- Error handling for new response format
-
Configure for Production:
- Set
NODE_ENV=production - Use proper ALLOWED_ORIGINS
- Configure HTTPS (Phase 2)
- Set up monitoring (Phase 4)
- Set
-
Testing:
- Test authentication flow
- Test WebSocket connections
- Test rate limiting
- Test error handling
Issues?
- Check
PROGRESS.mdfor known issues - Review
SESSION_SUMMARY.mdfor breaking changes - Verify
.envconfiguration - Check server logs for detailed errors
Scripts Available:
npm run dev- Start in development modenpm run generate-secret- Generate JWT secretnpm run create-admin- Create admin usercd server && npm start- Start server in production
- Dependencies installed
- JWT_SECRET generated and in
.env - ALLOWED_ORIGINS configured
- Admin user created
- Server starts without errors
- Can login via API
- Can access protected endpoints
- Frontend loads and connects
- WebSocket authentication works
π You're all set! The CloudNet Panel is now running with enhanced security.
Security Score: 7.5/10 (from 6.5/10)
Phase 1 Progress: 86% Complete
Next: Complete Phase 1 and move to Infrastructure (Phase 2)