A production-grade infrastructure automation system for secure provisioning and management of virtual private servers on Proxmox VE.
The Proxmox VPS Control Panel is a Node.js/Express.js application that runs directly on your Proxmox host with root privileges. It provides a secure REST API and web interface for creating, managing, and deleting VPS instances with automatic SSH port forwarding and IP detection.
- Web Interface: Modern, responsive web panel for easy VPS management
- Automated VPS Provisioning: Clone template VMs with custom CPU, RAM, and disk configurations
- Automatic SSH Access: Assigns unique SSH ports (2200-2299) with iptables NAT forwarding
- IP Detection: Polls for DHCP-assigned IP addresses via Cloud-Init
- Rollback on Failure: Automatic cleanup of partial infrastructure on any error
- JWT Authentication: Secure token-based authentication with bcrypt password hashing
- Rate Limiting: Protection against brute-force and abuse
- State Reconciliation: Startup reconciliation to detect orphaned VMs and invalid records
Routes → Middleware → Services → System Layer (qm, iptables)
- Routes: HTTP request handling and response formatting
- Middleware: Authentication, validation, rate limiting
- Services: Business logic, orchestration, rollback handling
- System Layer: Safe execution of Proxmox CLI commands
- Proxmox VE host (Debian-based)
- Node.js LTS (v20+)
- Root access on Proxmox host
- Template VM configured with Cloud-Init
- Nginx Proxy Manager (recommended for HTTPS access)
# Install Node.js LTS
curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
apt-get install -y nodejs
# Verify installation
node --version
npm --version# Create application directory
mkdir -p /opt/vps-panel
cd /opt/vps-panel
# Copy application files to /opt/vps-panel
# (Upload your project files here)
# Install dependencies
npm install# Copy example environment file
cp .env.example .env
# Generate JWT secret
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Generate admin password hash (replace 'your-secure-password' with your actual password)
node -e "const bcrypt = require('bcrypt'); bcrypt.hash('your-secure-password', 12).then(console.log)"
# Edit .env file with your values
nano .envRequired Configuration:
# Server
PORT=3000
BIND_ADDRESS=127.0.0.1
# Authentication (REPLACE THESE!)
JWT_SECRET=<generated-secret-from-above>
ADMIN_USERNAME=admin
ADMIN_PASSWORD_HASH=<generated-hash-from-above>
# Proxmox
TEMPLATE_VMID=100 # Your template VM ID
VMID_MIN=200
VMID_MAX=999
PROTECTED_VMIDS=100,101,102 # Include template and critical VMs
# SSH Ports
SSH_PORT_MIN=2200
SSH_PORT_MAX=2299
# Timeouts
IP_POLL_TIMEOUT=60000 # 60 seconds# Copy service file
cp vps-panel.service /etc/systemd/system/
# Reload systemd
systemctl daemon-reload
# Enable service to start on boot
systemctl enable vps-panel
# Start service
systemctl start vps-panel
# Check status
systemctl status vps-panel
# View logs
journalctl -u vps-panel -fInstall Nginx Proxy Manager or configure Nginx manually:
server {
listen 443 ssl http2;
server_name panel.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Once configured, access the web panel at:
- Local:
http://127.0.0.1:3000 - Production:
https://panel.example.com
Login with your configured admin credentials and start managing VPS instances through the intuitive web interface!
The web panel provides:
- Dashboard: Real-time statistics (Total VPS, Active VPS, CPU/RAM usage)
- VPS Creation: Easy form-based VPS provisioning
- VPS Management: View all VPS instances with detailed information
- SSH Commands: Copy-ready SSH connection commands for each VPS
- One-Click Actions: Delete VPS instances with confirmation
- Auto-Refresh: Dashboard updates every 30 seconds
- Responsive Design: Works on desktop, tablet, and mobile devices
# Login
curl -X POST https://panel.example.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-password"}'
# Response
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 3600
}
}curl -X POST https://panel.example.com/api/vps/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"name": "client-vps-1",
"cpu": 2,
"ram": 2048,
"disk": 30
}'
# Response
{
"success": true,
"data": {
"vmid": 201,
"ssh_command": "ssh root@your-host -p 2200",
"private_ip": "10.0.0.54",
"ssh_port": 2200
}
}curl -X GET https://panel.example.com/api/vps/list \
-H "Authorization: Bearer YOUR_TOKEN"
# Response
{
"success": true,
"data": [
{
"vmid": 201,
"name": "client-vps-1",
"private_ip": "10.0.0.54",
"ssh_port": 2200,
"cpu": 2,
"ram": 2048,
"disk": 30,
"created_at": "2026-02-13T10:30:00.000Z",
"status": "active"
}
]
}curl -X DELETE https://panel.example.com/api/vps/201 \
-H "Authorization: Bearer YOUR_TOKEN"
# Response
{
"success": true,
"data": {
"message": "VPS deleted successfully"
}
}curl -X GET https://panel.example.com/api/health
# Response
{
"success": true,
"data": {
"status": "healthy",
"uptime": 3600,
"proxmox": "connected",
"persistence": "ok"
}
}- VPS Metadata:
/opt/vps-panel/data/vps.json - Configuration:
/opt/vps-panel/.env - iptables Rules:
/etc/iptables/rules.v4
#!/bin/bash
# backup-vps-panel.sh
BACKUP_DIR="/backup/vps-panel"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# Backup VPS data
cp /opt/vps-panel/data/vps.json $BACKUP_DIR/vps_$DATE.json
# Backup environment config
cp /opt/vps-panel/.env $BACKUP_DIR/env_$DATE
# Backup iptables rules
iptables-save > $BACKUP_DIR/iptables_$DATE.rules
# Keep only last 7 days
find $BACKUP_DIR -type f -mtime +7 -delete
echo "Backup completed: $BACKUP_DIR"# Add to crontab
crontab -e
# Run daily at 2 AM
0 2 * * * /opt/vps-panel/backup-vps-panel.sh# Stop service
systemctl stop vps-panel
# Restore VPS data
cp /backup/vps-panel/vps_YYYYMMDD_HHMMSS.json /opt/vps-panel/data/vps.json
# Restore environment config
cp /backup/vps-panel/env_YYYYMMDD_HHMMSS /opt/vps-panel/.env
# Restore iptables rules
iptables-restore < /backup/vps-panel/iptables_YYYYMMDD_HHMMSS.rules
netfilter-persistent save
# Start service
systemctl start vps-panel
# Verify reconciliation
journalctl -u vps-panel -n 50# Check service status
systemctl status vps-panel
# View detailed logs
journalctl -u vps-panel -n 100 --no-pager
# Check environment file
cat /opt/vps-panel/.env
# Test Node.js manually
cd /opt/vps-panel
node server.js# Check Proxmox connectivity
qm list
# Check template VM exists
qm status 100
# Check available VMIDs
qm list | grep -E "20[0-9]|2[1-9][0-9]|[3-9][0-9]{2}"
# Check SSH port availability
iptables -t nat -L VPS_PANEL_NAT -n --line-numbers
# View application logs
journalctl -u vps-panel -f# Verify guest agent is installed in template
qm agent 100 ping
# Check Cloud-Init configuration
qm cloudinit dump 100 user
# Increase timeout in .env
IP_POLL_TIMEOUT=90000 # 90 seconds# Check iptables rules
iptables -t nat -L VPS_PANEL_NAT -n -v
# Verify chain exists
iptables -t nat -L PREROUTING -n | grep VPS_PANEL_NAT
# Test port forwarding
ssh root@proxmox-host -p 2200
# Check VM IP is correct
qm guest cmd 201 network-get-interfaces# View reconciliation logs
journalctl -u vps-panel | grep reconciliation
# Manually clean orphaned VM
qm stop 205
qm destroy 205
# Remove orphaned iptables rule
iptables -t nat -D VPS_PANEL_NAT -p tcp --dport 2205 -j DNAT --to-destination 10.0.0.55:22
netfilter-persistent save- Never expose panel directly: Always use Nginx reverse proxy with HTTPS
- Strong passwords: Use 16+ character passwords for admin account
- Rotate JWT secret: Change JWT_SECRET periodically
- Monitor logs: Watch for failed authentication attempts
- Firewall rules: Restrict access to panel port (3000) to localhost only
- Regular updates: Keep Node.js and dependencies updated
- Login attempts: 5 per minute per IP
- VPS creation: 5 per hour per admin
Always include critical VMs in PROTECTED_VMIDS:
- Template VMs
- Production infrastructure VMs
- Database VMs
IMPORTANT: This application uses in-memory locking for resource allocation. Do NOT run multiple instances or use PM2 cluster mode. Only one process should run at a time.
- Single Proxmox host (no cluster support in v1)
- Single admin user (multi-tenant support planned)
- JSON file storage (database migration planned)
# Monitor application health
curl http://127.0.0.1:3000/api/health# Real-time logs
journalctl -u vps-panel -f
# Error logs only
journalctl -u vps-panel -p err -f
# Last 100 lines
journalctl -u vps-panel -n 100# Check process status
systemctl status vps-panel
# Memory usage
ps aux | grep "node server.js"
# Disk usage
du -sh /opt/vps-panel/data/# Stop service
systemctl stop vps-panel
# Backup current version
cp -r /opt/vps-panel /opt/vps-panel.backup
# Update files
cd /opt/vps-panel
git pull # or copy new files
# Install dependencies
npm install
# Start service
systemctl start vps-panel
# Verify
systemctl status vps-panelLogs are managed by systemd journald. Configure retention:
# Edit journald config
nano /etc/systemd/journald.conf
# Set limits
SystemMaxUse=500M
MaxRetentionSec=7day
# Restart journald
systemctl restart systemd-journaldFor issues, feature requests, or contributions, please visit the project repository.
MIT - see LICENSE for details.
Production Infrastructure Software - Handle with care. Every operation affects real compute resources.