Frontend Separation Deployment
This guide will help you independently deploy PPanel frontend applications and connect them to the deployed backend service.
Overview
Frontend separation deployment allows you to deploy PPanel frontend applications on independent servers or CDN, communicating with backend services through APIs.
PPanel frontend includes two independent applications:
- User Web (
ppanel-user-web): User-facing interface - Admin Web (
ppanel-admin-web): Administrator backend management interface
Advantages
- 🚀 Leverage CDN to accelerate static resource access
- 🌍 Support multi-region distribution
- 📦 Independent frontend deployment without affecting backend services
- 🔄 Facilitate rapid frontend iteration and updates
- 🎨 Modern tech stack (React 19, TypeScript, TailwindCSS 4)
Prerequisites
- Completed Backend Deployment
- Backend API address (e.g.,
https://api.your-domain.com) - Frontend domains:
- User Web:
https://user.your-domain.com - Admin Web:
https://admin.your-domain.com
- User Web:
Tech Stack
- Runtime: Bun (recommended) / Node.js 20+
- Build Tool: Vite 6
- Framework: React 19 + TypeScript
- Router: TanStack Router
- Styling: TailwindCSS 4
- State Management: Zustand
- i18n: i18next
- Monorepo: Turborepo
Deployment Methods
Method 1: Build from Source (Recommended)
1. Environment Setup
Install Bun (recommended):
# Linux/macOS
curl -fsSL https://bun.sh/install | bash
# Windows (WSL2)
curl -fsSL https://bun.sh/install | bash
# Verify installation
bun --versionOr use Node.js (requires 20+):
# Check Node.js version
node --version # Should be v20 or higher2. Clone Repository
git clone https://github.com/perfect-panel/frontend.git
cd frontend3. Install Dependencies
# Using Bun (recommended, faster)
bun install
# Or using npm
npm install
# Or using pnpm
pnpm install4. Configure Environment Variables
Create environment configuration files in application directories.
Admin Web Config (apps/admin/.env.production):
# Backend API address (required)
VITE_API_BASE_URL=https://api.your-domain.com
# CDN address (optional, for accelerating static resources)
VITE_CDN_URL=https://cdn.jsdmirror.com
# Enable tutorial documentation (optional)
VITE_TUTORIAL_DOCUMENT=true
# Development default credentials (leave empty in production)
VITE_USER_EMAIL=
VITE_USER_PASSWORD=User Web Config (apps/user/.env.production):
# Backend API address (required)
VITE_API_BASE_URL=https://api.your-domain.com
# CDN address (optional)
VITE_CDN_URL=https://cdn.jsdmirror.com
# Enable tutorial documentation (optional)
VITE_TUTORIAL_DOCUMENT=true
# Development default credentials (leave empty in production)
VITE_USER_EMAIL=
VITE_USER_PASSWORD=5. Build Applications
Build all applications:
# Using Bun
bun run build
# Or using npm
npm run buildBuild specific application:
# Navigate to application directory
cd apps/admin # or apps/user
# Build
bun run build # or npm run buildAfter build completes, static files will be output to:
- Admin Web:
apps/admin/dist/ - User Web:
apps/user/dist/
6. Preview Build
# In application directory
bun run serve # or npm run serve
# Default access address:
# Admin Web: http://localhost:4173
# User Web: http://localhost:4173Method 2: Deploy with Vercel (One-Click)
Admin Web Deployment
Click the button below to deploy to Vercel with one click:
User Web Deployment
After deployment, configure environment variables in Vercel console:
VITE_API_BASE_URL: Your backend API addressVITE_CDN_URL: CDN address (optional)
Method 3: Deploy with Netlify
1. Install Netlify CLI
npm install -g netlify-cli2. Login to Netlify
netlify login3. Deploy Application
# Admin Web
cd apps/admin
bun run build
netlify deploy --prod --dir=dist
# User Web
cd apps/user
bun run build
netlify deploy --prod --dir=dist4. Configure Environment Variables
Add in Netlify console under Site settings → Build & deploy → Environment:
VITE_API_BASE_URLVITE_CDN_URL
Method 4: Deploy with Cloudflare Pages
1. Connect GitHub Repository
Login to Cloudflare Dashboard → Workers & Pages → Create application → Pages → Connect to Git
2. Configure Build Settings
Admin Web:
- Framework preset: None
- Build command:
cd .. && bun install && cd apps/admin && bun run build - Build output directory:
apps/admin/dist - Root directory:
apps/admin
User Web:
- Framework preset: None
- Build command:
cd .. && bun install && cd apps/user && bun run build - Build output directory:
apps/user/dist - Root directory:
apps/user
3. Configure Environment Variables
Add in Settings → Environment variables:
VITE_API_BASE_URLVITE_CDN_URL
Self-Hosted Server Deployment
Using Nginx
1. Install Nginx
# Ubuntu/Debian
sudo apt update
sudo apt install nginx -y
# CentOS/RHEL
sudo yum install nginx -y2. Upload Build Files
# Create directories
sudo mkdir -p /var/www/ppanel/{admin,user}
# Upload build files
sudo cp -r apps/admin/dist/* /var/www/ppanel/admin/
sudo cp -r apps/user/dist/* /var/www/ppanel/user/
# Set permissions
sudo chown -R www-data:www-data /var/www/ppanel3. Configure Nginx
Admin Web Config (/etc/nginx/sites-available/ppanel-admin):
server {
listen 80;
server_name admin.your-domain.com;
root /var/www/ppanel/admin;
index index.html;
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_vary on;
gzip_min_length 1024;
# Static resource caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# SPA routing support
location / {
try_files $uri $uri/ /index.html;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
}User Web Config (/etc/nginx/sites-available/ppanel-user):
server {
listen 80;
server_name user.your-domain.com;
root /var/www/ppanel/user;
index index.html;
# Other config same as admin web
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location / {
try_files $uri $uri/ /index.html;
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}4. Enable Sites
# Enable sites
sudo ln -s /etc/nginx/sites-available/ppanel-admin /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/ppanel-user /etc/nginx/sites-enabled/
# Test configuration
sudo nginx -t
# Reload Nginx
sudo systemctl reload nginx5. Configure HTTPS (Recommended)
Use Certbot to automatically configure SSL certificates:
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Obtain certificates
sudo certbot --nginx -d admin.your-domain.com
sudo certbot --nginx -d user.your-domain.com
# Test auto-renewal
sudo certbot renew --dry-runUsing Caddy
Caddy automatically handles HTTPS with simpler configuration.
1. Install Caddy
# Ubuntu/Debian
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy2. Configure Caddyfile
Create /etc/caddy/Caddyfile:
admin.your-domain.com {
root * /var/www/ppanel/admin
encode gzip
file_server
try_files {path} /index.html
@static {
path *.js *.css *.png *.jpg *.jpeg *.gif *.ico *.svg *.woff *.woff2 *.ttf *.eot
}
header @static Cache-Control "public, max-age=31536000, immutable"
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
}
}
user.your-domain.com {
root * /var/www/ppanel/user
encode gzip
file_server
try_files {path} /index.html
@static {
path *.js *.css *.png *.jpg *.jpeg *.gif *.ico *.svg *.woff *.woff2 *.ttf *.eot
}
header @static Cache-Control "public, max-age=31536000, immutable"
header {
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
}
}3. Start Caddy
sudo systemctl restart caddy
sudo systemctl enable caddyCDN Configuration
Cloudflare Configuration
Add domain to Cloudflare
Configure DNS records pointing to origin server
Enable optimization options:
- Auto Minify: Enable JavaScript, CSS, HTML minification
- Brotli: Enable Brotli compression
- Rocket Loader: Enable JS async loading (optional)
- Caching Level: Set to Standard
Configure page rules:
*your-domain.com/* - Cache Level: Cache Everything - Edge Cache TTL: 1 month - Browser Cache TTL: Respect Existing Headers
Alibaba Cloud CDN
- Create CDN acceleration domain
- Configure origin server: Point to frontend server
- Configure caching rules:
- Static files (js, css, images): Cache 1 year
- HTML files: Cache 5 minutes or no cache
- Enable HTTPS and HTTP/2
Environment Variables
| Variable | Description | Required | Default | Example |
|---|---|---|---|---|
VITE_API_BASE_URL | Backend API address | ✅ | - | https://api.your-domain.com |
VITE_CDN_URL | CDN address | ❌ | https://cdn.jsdmirror.com | https://cdn.your-domain.com |
VITE_TUTORIAL_DOCUMENT | Enable tutorial docs | ❌ | true | true / false |
VITE_USER_EMAIL | Default login email (dev only) | ❌ | - | - |
VITE_USER_PASSWORD | Default login password (dev only) | ❌ | - | - |
Verify Deployment
Check Frontend Service
# Access frontend addresses
curl -I https://admin.your-domain.com
curl -I https://user.your-domain.com
# Expected output
# HTTP/2 200
# content-type: text/htmlCheck API Connection
Open frontend address in browser, open developer tools:
- Check Network tab
- Verify API requests are successful
- Confirm request addresses are correct (
https://api.your-domain.com) - Check response data is normal
Check Build Version
Access /version.lock file to view currently deployed version:
curl https://admin.your-domain.com/version.lock
# Example output: 1.2.0Performance Optimization
1. Enable HTTP/2
In Nginx:
listen 443 ssl http2;2. Enable Brotli Compression
# Install Nginx Brotli module
sudo apt install libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static -yIn Nginx configuration:
brotli on;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml;
brotli_comp_level 6;3. Preload Critical Resources
Vite automatically handles this during build, adding <link rel="modulepreload"> in index.html.
4. Enable Service Worker
Frontend has built-in PWA support, Service Worker caching is automatically enabled after build.
5. Use CDN Acceleration
Configure VITE_CDN_URL environment variable to load static resources from CDN.
Troubleshooting
API Request Failed
Issue: Frontend cannot connect to backend API
Solution:
- Check if
VITE_API_BASE_URLis correctly configured - Check if backend CORS configuration allows frontend domain
- Open browser console for specific error messages
- Use
curlto test if backend API is accessible
curl https://api.your-domain.com/api/healthPage Route 404
Issue: Refreshing page or directly accessing sub-route returns 404
Solution: Ensure web server has SPA fallback configured
# Nginx
try_files $uri $uri/ /index.html;
# Apache (.htaccess)
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]Static Resource Loading Failed
Issue: JS/CSS files 404 or cannot load
Solution:
- Check file permissions
- Check if Nginx
rootpath is correct - Clear browser cache
- Check CDN configuration
Build Failed
Issue: bun run build or npm run build fails
Solution:
- Ensure Node.js version >= 20
- Delete
node_modulesand lock file, reinstallbashrm -rf node_modules bun.lockb bun install - Check for syntax errors or type errorsbash
bun run check
Update Deployment
Update from Source
# Pull latest code
git pull origin main
# Reinstall dependencies
bun install
# Rebuild
bun run build
# Update files
sudo rm -rf /var/www/ppanel/admin
sudo rm -rf /var/www/ppanel/user
sudo cp -r apps/admin/dist /var/www/ppanel/admin
sudo cp -r apps/user/dist /var/www/ppanel/user
# Clear CDN cache (if using CDN)Vercel Update
Vercel automatically monitors GitHub repository changes and deploys automatically. Can also trigger manually:
vercel --prodNetlify Update
cd apps/admin # or apps/user
bun run build
netlify deploy --prodSecurity Recommendations
- Enable HTTPS: Must use SSL/TLS certificates
- Configure CSP: Content Security Policynginx
add_header Content-Security-Policy "default-src 'self'; connect-src 'self' https://api.your-domain.com; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval';"; - Set Security Headers: Already included in Nginx configuration
- Disable Directory Browsing:
Options -Indexes(Apache) orautoindex off;(Nginx) - Limit File Upload Size:nginx
client_max_body_size 10M;
Monitoring and Analytics
Add Web Analytics
Supports Google Analytics, Umami, Plausible, etc.
Configuration: Add tracking code in index.html or configure via environment variables.
Error Tracking
Frontend supports integrating Sentry for error tracking (needs code configuration).
Development and Production
Local Development
# Use development server
cd apps/admin # or apps/user
bun run dev
# Admin Web runs on http://localhost:3001 by default
# User Web runs on http://localhost:3000 by defaultDevelopment environment uses Vite's proxy feature to proxy API requests to backend.
Preview Production Build
# Preview after build
bun run build
bun run serveNext Steps
- Backend Separation Deployment - If backend not yet deployed
- Node Agent Installation - Deploy node service
- Feature Documentation - Learn feature usage