Server Setup
This guide covers deploying the Siyahfy platform to a production Linux server.
Server Requirements
| Component | Minimum | Recommended |
|---|---|---|
| OS | Ubuntu 20.04 LTS | Ubuntu 22.04 LTS |
| CPU | 2 vCPUs | 4 vCPUs |
| RAM | 4 GB | 8 GB |
| Storage | 40 GB SSD | 80 GB SSD |
| Node.js | 18.x | 20.x LTS |
| PostgreSQL | 14.x | 16.x |
| Redis | 7.x (optional) | 7.x |
| Nginx | 1.18+ | Latest stable |
| PM2 | 5.x | Latest |
Initial Server Setup
1. System Updates and Dependencies
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git build-essential nginx certbot python3-certbot-nginx ufw2. Install Node.js
# Install Node.js 20.x via NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Verify
node --version # v20.x.x
npm --version # 10.x.x3. Install PM2
sudo npm install -g pm2
# Set PM2 to start on boot
pm2 startup systemd4. Clone the Repository
cd /var/www
sudo git clone https://github.com/your-org/siyahfy.git
sudo chown -R $USER:$USER /var/www/siyahfy
cd /var/www/siyahfyApplication Setup
Install Dependencies
# Install dependencies for each app
cd /var/www/siyahfy/backend.siyahfy.com && npm install
cd /var/www/siyahfy/app.siyahfy.com && npm install && npm run build
cd /var/www/siyahfy/editor.siyahfy.com && npm install && npm run build
cd /var/www/siyahfy/studio.siyahfy.com && npm install && npm run build
cd /var/www/siyahfy/siyahfy.com && npm install && npm run build
cd /var/www/siyahfy/siyahfy-theme-2502 && npm install && npm run buildConfigure Environment Variables
Copy the example environment files and fill in production values for each app. See the Environment Variables page for the complete reference.
# Backend
cp /var/www/siyahfy/backend.siyahfy.com/.env.example /var/www/siyahfy/backend.siyahfy.com/.env
nano /var/www/siyahfy/backend.siyahfy.com/.env
# Vendor Dashboard
cp /var/www/siyahfy/app.siyahfy.com/.env.example /var/www/siyahfy/app.siyahfy.com/.env.local
nano /var/www/siyahfy/app.siyahfy.com/.env.local
# Repeat for other apps...PM2 Process Management
Ecosystem Configuration
Create an ecosystem.config.js file at the project root:
// /var/www/siyahfy/ecosystem.config.js
module.exports = {
apps: [
{
name: 'backend',
cwd: '/var/www/siyahfy/backend.siyahfy.com',
script: 'index.js',
instances: 2,
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3003
},
max_memory_restart: '500M',
error_file: '/var/log/pm2/backend-error.log',
out_file: '/var/log/pm2/backend-out.log'
},
{
name: 'app-dashboard',
cwd: '/var/www/siyahfy/app.siyahfy.com',
script: 'node_modules/.bin/next',
args: 'start -p 3004',
instances: 1,
env: {
NODE_ENV: 'production'
},
max_memory_restart: '500M',
error_file: '/var/log/pm2/app-error.log',
out_file: '/var/log/pm2/app-out.log'
},
{
name: 'editor',
cwd: '/var/www/siyahfy/editor.siyahfy.com',
script: 'node_modules/.bin/next',
args: 'start -p 3001',
instances: 1,
env: {
NODE_ENV: 'production'
},
max_memory_restart: '400M',
error_file: '/var/log/pm2/editor-error.log',
out_file: '/var/log/pm2/editor-out.log'
},
{
name: 'studio',
cwd: '/var/www/siyahfy/studio.siyahfy.com',
script: 'node_modules/.bin/next',
args: 'start -p 3012',
instances: 1,
env: {
NODE_ENV: 'production'
},
max_memory_restart: '400M',
error_file: '/var/log/pm2/studio-error.log',
out_file: '/var/log/pm2/studio-out.log'
},
{
name: 'marketing-site',
cwd: '/var/www/siyahfy/siyahfy.com',
script: 'node_modules/.bin/next',
args: 'start -p 3006',
instances: 1,
env: {
NODE_ENV: 'production'
},
max_memory_restart: '400M',
error_file: '/var/log/pm2/marketing-error.log',
out_file: '/var/log/pm2/marketing-out.log'
},
{
name: 'store-theme',
cwd: '/var/www/siyahfy/siyahfy-theme-2502',
script: 'node_modules/.bin/next',
args: 'start -p 3002',
instances: 1,
env: {
NODE_ENV: 'production'
},
max_memory_restart: '400M',
error_file: '/var/log/pm2/store-error.log',
out_file: '/var/log/pm2/store-out.log'
}
]
}PM2 Commands
# Start all apps
pm2 start ecosystem.config.js
# View running processes
pm2 list
# View logs
pm2 logs # All apps
pm2 logs backend # Specific app
# Restart apps
pm2 restart all # Restart everything
pm2 restart backend # Restart specific app
pm2 reload backend # Zero-downtime reload (cluster mode)
# Stop apps
pm2 stop all
pm2 stop backend
# Save current process list (survives reboots)
pm2 save
# Monitor resource usage
pm2 monitNginx Reverse Proxy
Main Configuration
Edit /etc/nginx/nginx.conf to increase the upload limit:
http {
# ...existing settings...
client_max_body_size 50M;
}Site Configurations
Create a config file for each subdomain in /etc/nginx/sites-available/.
backend.siyahfy.com
# /etc/nginx/sites-available/backend.siyahfy.com
server {
listen 80;
server_name backend.siyahfy.com;
location / {
proxy_pass http://127.0.0.1:3003;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
}
}app.siyahfy.com
# /etc/nginx/sites-available/app.siyahfy.com
server {
listen 80;
server_name app.siyahfy.com;
location / {
proxy_pass http://127.0.0.1:3004;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
}
}editor.siyahfy.com
# /etc/nginx/sites-available/editor.siyahfy.com
server {
listen 80;
server_name editor.siyahfy.com;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
}
}studio.siyahfy.com
# /etc/nginx/sites-available/studio.siyahfy.com
server {
listen 80;
server_name studio.siyahfy.com;
location / {
proxy_pass http://127.0.0.1:3012;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
}
}Enable Sites
# Create symlinks to enable each site
sudo ln -s /etc/nginx/sites-available/backend.siyahfy.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/app.siyahfy.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/editor.siyahfy.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/studio.siyahfy.com /etc/nginx/sites-enabled/
# Test configuration
sudo nginx -t
# Reload Nginx
sudo systemctl reload nginxSSL/HTTPS with Let’s Encrypt
Obtain Certificates
# Install certificates for all subdomains
sudo certbot --nginx -d backend.siyahfy.com
sudo certbot --nginx -d app.siyahfy.com
sudo certbot --nginx -d editor.siyahfy.com
sudo certbot --nginx -d studio.siyahfy.com
# Or obtain a wildcard certificate (requires DNS validation)
sudo certbot certonly --manual --preferred-challenges dns \
-d "*.siyahfy.com" -d "siyahfy.com"Certbot automatically modifies the Nginx config to add SSL settings and a redirect from HTTP to HTTPS.
Auto-Renewal
Certbot installs a systemd timer for auto-renewal. Verify it is active:
sudo systemctl status certbot.timer
# Test renewal
sudo certbot renew --dry-runDomain Configuration
DNS Records
Point all subdomains to your server IP. Add A records in your DNS provider:
| Type | Name | Value | TTL |
|---|---|---|---|
| A | @ | YOUR_SERVER_IP | 3600 |
| A | app | YOUR_SERVER_IP | 3600 |
| A | backend | YOUR_SERVER_IP | 3600 |
| A | editor | YOUR_SERVER_IP | 3600 |
| A | studio | YOUR_SERVER_IP | 3600 |
| A | store | YOUR_SERVER_IP | 3600 |
| A | docs | YOUR_SERVER_IP | 3600 |
Alternatively, use a wildcard record:
| Type | Name | Value | TTL |
|---|---|---|---|
| A | * | YOUR_SERVER_IP | 3600 |
Firewall Rules
UFW Configuration
# Enable UFW
sudo ufw enable
# Allow SSH (important: do this first to avoid lockout)
sudo ufw allow OpenSSH
# Allow HTTP and HTTPS
sudo ufw allow 'Nginx Full'
# Deny direct access to application ports from outside
# (traffic should flow through Nginx only)
sudo ufw deny 3001
sudo ufw deny 3002
sudo ufw deny 3003
sudo ufw deny 3004
sudo ufw deny 3006
sudo ufw deny 3012
# Allow PostgreSQL only from localhost (default)
# Do NOT open port 5432 to the internet
# Check status
sudo ufw status verboseExpected Firewall Rules
To Action From
-- ------ ----
22/tcp (OpenSSH) ALLOW IN Anywhere
80,443/tcp (Nginx Full) ALLOW IN Anywhere
3001 DENY IN Anywhere
3002 DENY IN Anywhere
3003 DENY IN Anywhere
3004 DENY IN Anywhere
3006 DENY IN Anywhere
3012 DENY IN AnywhereHealth Checks
PM2 Health Check Script
Create a health check script to verify all services are running:
#!/bin/bash
# /var/www/siyahfy/health-check.sh
echo "=== Siyahfy Health Check ==="
echo ""
# Check PM2 processes
echo "PM2 Processes:"
pm2 list
echo ""
# Check each service
services=(
"backend:3003"
"app-dashboard:3004"
"editor:3001"
"studio:3012"
"marketing-site:3006"
"store-theme:3002"
)
for service in "${services[@]}"; do
name="${service%%:*}"
port="${service##*:}"
status=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$port" 2>/dev/null)
if [ "$status" = "200" ] || [ "$status" = "302" ]; then
echo "[OK] $name (port $port) - HTTP $status"
else
echo "[FAIL] $name (port $port) - HTTP $status"
fi
done
echo ""
# Check PostgreSQL
if pg_isready -q; then
echo "[OK] PostgreSQL is running"
else
echo "[FAIL] PostgreSQL is not running"
fi
# Check Redis
if redis-cli ping > /dev/null 2>&1; then
echo "[OK] Redis is running"
else
echo "[WARN] Redis is not running (optional)"
fi
# Check Nginx
if systemctl is-active --quiet nginx; then
echo "[OK] Nginx is running"
else
echo "[FAIL] Nginx is not running"
fi
# Check disk space
echo ""
echo "Disk Usage:"
df -h / | tail -1# Make it executable
chmod +x /var/www/siyahfy/health-check.sh
# Run it
./health-check.shAutomated Monitoring with PM2
PM2 provides built-in monitoring. For production, consider connecting to PM2’s monitoring dashboard:
# Real-time monitoring in the terminal
pm2 monit
# Save process list for auto-restart on reboot
pm2 save
pm2 startupNginx Health Check Endpoint
Add a simple health endpoint to the backend Nginx config:
# Add inside the server block for backend.siyahfy.com
location /health {
proxy_pass http://127.0.0.1:3003/health;
access_log off;
}You can then monitor this endpoint with uptime services like UptimeRobot, Pingdom, or a simple cron job:
# Add to crontab: check health every 5 minutes
*/5 * * * * curl -sf http://localhost:3003/health || pm2 restart backendDeployment Workflow
Manual Deployment
cd /var/www/siyahfy
# Pull latest changes
git pull origin main
# Reinstall dependencies and rebuild
cd backend.siyahfy.com && npm install
cd ../app.siyahfy.com && npm install && npm run build
cd ../editor.siyahfy.com && npm install && npm run build
cd ../studio.siyahfy.com && npm install && npm run build
cd ../siyahfy.com && npm install && npm run build
cd ../siyahfy-theme-2502 && npm install && npm run build
# Restart all processes
cd /var/www/siyahfy
pm2 restart all
# Verify
pm2 listDeployment Script
Create a reusable deployment script:
#!/bin/bash
# /var/www/siyahfy/deploy.sh
set -e
BASE_DIR="/var/www/siyahfy"
cd "$BASE_DIR"
echo "Pulling latest changes..."
git pull origin main
echo "Building backend..."
cd "$BASE_DIR/backend.siyahfy.com" && npm install
echo "Building vendor dashboard..."
cd "$BASE_DIR/app.siyahfy.com" && npm install && npm run build
echo "Building editor..."
cd "$BASE_DIR/editor.siyahfy.com" && npm install && npm run build
echo "Building studio..."
cd "$BASE_DIR/studio.siyahfy.com" && npm install && npm run build
echo "Building marketing site..."
cd "$BASE_DIR/siyahfy.com" && npm install && npm run build
echo "Building store theme..."
cd "$BASE_DIR/siyahfy-theme-2502" && npm install && npm run build
echo "Restarting PM2 processes..."
cd "$BASE_DIR"
pm2 reload ecosystem.config.js
echo "Deployment complete!"
pm2 listchmod +x /var/www/siyahfy/deploy.sh
./deploy.sh