Skip to Content
DeploymentServer Setup

Server Setup

This guide covers deploying the Siyahfy platform to a production Linux server.

Server Requirements

ComponentMinimumRecommended
OSUbuntu 20.04 LTSUbuntu 22.04 LTS
CPU2 vCPUs4 vCPUs
RAM4 GB8 GB
Storage40 GB SSD80 GB SSD
Node.js18.x20.x LTS
PostgreSQL14.x16.x
Redis7.x (optional)7.x
Nginx1.18+Latest stable
PM25.xLatest

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 ufw

2. 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.x

3. Install PM2

sudo npm install -g pm2 # Set PM2 to start on boot pm2 startup systemd

4. 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/siyahfy

Application 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 build

Configure 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 monit

Nginx 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 nginx

SSL/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-run

Domain Configuration

DNS Records

Point all subdomains to your server IP. Add A records in your DNS provider:

TypeNameValueTTL
A@YOUR_SERVER_IP3600
AappYOUR_SERVER_IP3600
AbackendYOUR_SERVER_IP3600
AeditorYOUR_SERVER_IP3600
AstudioYOUR_SERVER_IP3600
AstoreYOUR_SERVER_IP3600
AdocsYOUR_SERVER_IP3600

Alternatively, use a wildcard record:

TypeNameValueTTL
A*YOUR_SERVER_IP3600

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 verbose

Expected 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 Anywhere

Health 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.sh

Automated 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 startup

Nginx 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 backend

Deployment 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 list

Deployment 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 list
chmod +x /var/www/siyahfy/deploy.sh ./deploy.sh