# Production Installation

This guide covers deploying CloudPOS to a production server.

# Prerequisites

  • ✅ Server with Ubuntu 22.04 LTS (or similar Linux distribution)
  • ✅ Domain name configured
  • ✅ SSL certificate (Let's Encrypt recommended)
  • ✅ Node.js 18+ installed
  • ✅ MySQL 8+ installed
  • ✅ Nginx installed
  • ✅ PM2 installed (npm install -g pm2)

# Step 1: Server Preparation

# 1.1 Update System

sudo apt update
sudo apt upgrade -y

# 1.2 Install Required Software

# Install Node.js 18
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

# Install MySQL
sudo apt install mysql-server -y
sudo mysql_secure_installation

# Install Nginx
sudo apt install nginx -y

# Install PM2
sudo npm install -g pm2

# Install Git
sudo apt install git -y

# 1.3 Create Application User

# Create a non-root user for the application
sudo adduser cloudpos
sudo usermod -aG sudo cloudpos

# Switch to the new user
su - cloudpos

# Step 2: Deploy Application

# 2.1 Clone or Upload Project

# Option 1: Clone from Git
cd /var/www
sudo git clone <your-repo-url> cloudpos
sudo chown -R cloudpos:cloudpos cloudpos
cd cloudpos

# Option 2: Upload via SFTP/SCP
# Upload project files to /var/www/cloudpos

# 2.2 Install Dependencies

# Install root dependencies
npm install

# Install server dependencies
cd server
npm install --production

# Install client dependencies
cd ../client
npm install --production

# Step 3: Configure Environment

# 3.1 Create Production .env File

cd /var/www/cloudpos
nano .env

Add production environment variables (see Environment Configuration):

NODE_ENV=production
PORT=3000

# Database
DATABASE_URL="mysql://cloudpos:STRONG_PASSWORD@localhost:3306/cloudpos"

# JWT Secrets (generate strong random strings)
JWT_SECRET=your-super-secret-jwt-key-min-32-chars
JWT_EXPIRES_IN=15m
JWT_REFRESH_SECRET=your-super-secret-refresh-key-min-32-chars
JWT_REFRESH_EXPIRES_IN=7d

# CORS
CORS_ORIGIN=https://yourdomain.com

# Frontend URL
FRONTEND_URL=https://yourdomain.com

# Encryption Key (generate: openssl rand -base64 32)
ENCRYPTION_KEY=your-encryption-key-here

# SMTP (if using email)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_FROM_EMAIL=noreply@yourdomain.com
SMTP_FROM_NAME=CloudPOS

# Stripe (if using payments)
STRIPE_SECRET_KEY=sk_live_your_stripe_secret_key
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret

# Demo Mode (set to false for production)
DEMO_MODE=false

# Client Configuration
VITE_API_URL=https://yourdomain.com/api

# 3.2 Secure .env File

# Set proper permissions
chmod 600 .env
chown cloudpos:cloudpos .env

# Step 4: Setup Database

# 4.1 Create Database and User

sudo mysql -u root -p
CREATE DATABASE cloudpos CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'cloudpos'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD';
GRANT ALL PRIVILEGES ON cloudpos.* TO 'cloudpos'@'localhost';
FLUSH PRIVILEGES;
EXIT;

# 4.2 Run Migrations

cd /var/www/cloudpos/server
npm run prisma:generate
npm run prisma:migrate

# 4.3 Create Admin User

npm run prisma:seed:cms
# Or manually:
npx ts-node prisma/create-admin.ts

⚠️ Change default admin password immediately!

# Step 5: Build Application

# 5.1 Build Backend

cd /var/www/cloudpos/server
npm run build

# 5.2 Build Frontend

cd /var/www/cloudpos/client
npm run build

The built files will be in client/dist/.

# Step 6: Configure PM2

# 6.1 Create PM2 Ecosystem File

The project already includes ecosystem.config.js in the root. Update it if needed:

cd /var/www/cloudpos
nano ecosystem.config.js

# 6.2 Start Application with PM2

pm2 start ecosystem.config.js
pm2 save
pm2 startup

Follow the command output to enable PM2 on system boot.

# 6.3 Verify PM2 Status

pm2 status
pm2 logs cloudpos

# Step 7: Configure Nginx

# 7.1 Create Nginx Configuration

sudo nano /etc/nginx/sites-available/cloudpos

Add this configuration:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    
    # Redirect HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    # SSL Configuration
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # 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;

    # Client max body size (for file uploads)
    client_max_body_size 10M;

    # Proxy to API server
    location /api {
        proxy_pass http://localhost:3000;
        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;
    }

    # Serve static files (uploads)
    location /uploads {
        alias /var/www/cloudpos/server/uploads;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Serve frontend (React app)
    location / {
        root /var/www/cloudpos/client/dist;
        try_files $uri $uri/ /index.html;
        expires -1;
        add_header Cache-Control "no-cache, no-store, must-revalidate";
    }

    # Cache static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        root /var/www/cloudpos/client/dist;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

# 7.2 Enable Site

sudo ln -s /etc/nginx/sites-available/cloudpos /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

# Step 8: Setup SSL Certificate

# 8.1 Install Certbot

sudo apt install certbot python3-certbot-nginx -y

# 8.2 Obtain SSL Certificate

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Follow the prompts. Certbot will automatically configure Nginx.

# 8.3 Auto-Renewal

Certbot sets up auto-renewal automatically. Test it:

sudo certbot renew --dry-run

# Step 9: Configure Firewall

# Allow SSH
sudo ufw allow 22/tcp

# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable firewall
sudo ufw enable
sudo ufw status

# Step 10: File Permissions

# Set ownership
sudo chown -R cloudpos:cloudpos /var/www/cloudpos

# Set directory permissions
find /var/www/cloudpos -type d -exec chmod 755 {} \;

# Set file permissions
find /var/www/cloudpos -type f -exec chmod 644 {} \;

# Make uploads directory writable
chmod -R 775 /var/www/cloudpos/server/uploads

# Step 11: Verify Installation

# 11.1 Check Services

# Check PM2
pm2 status

# Check Nginx
sudo systemctl status nginx

# Check MySQL
sudo systemctl status mysql

# 11.2 Test URLs

  • Frontend: https://yourdomain.com
  • API: https://yourdomain.com/api
  • Admin: https://yourdomain.com/admin/login

# 11.3 Check Logs

# PM2 logs
pm2 logs cloudpos

# Nginx logs
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log

# Application logs
tail -f /var/www/cloudpos/logs/pm2-out.log
tail -f /var/www/cloudpos/logs/pm2-error.log

# Step 12: Post-Installation

  1. Change default admin password
  2. Configure payment gateway (see Payment Gateway)
  3. Configure email (see Email Notifications)
  4. Review security settings (see Security & Demo Mode)
  5. Run production checklist (see Production Checklist)

# Maintenance Commands

# Update Application

cd /var/www/cloudpos
git pull  # If using Git
npm install
cd server && npm install && npm run build
cd ../client && npm install && npm run build
pm2 restart cloudpos

# Database Backup

# Create backup
mysqldump -u cloudpos -p cloudpos > backup_$(date +%Y%m%d).sql

# Restore backup
mysql -u cloudpos -p cloudpos < backup_20240101.sql

# View Logs

# PM2 logs
pm2 logs cloudpos --lines 100

# Nginx logs
sudo tail -f /var/log/nginx/error.log

# Troubleshooting

# Application Not Starting

# Check PM2 status
pm2 status

# Check logs
pm2 logs cloudpos --err

# Restart application
pm2 restart cloudpos

# 502 Bad Gateway

  • Check if API server is running: pm2 status
  • Check API server logs: pm2 logs cloudpos
  • Verify Nginx proxy configuration

# SSL Certificate Issues

# Renew certificate manually
sudo certbot renew

# Check certificate status
sudo certbot certificates

Next Steps: See Production Checklist for pre-launch verification.