Production Deployment Guide

Complete server configuration documentation for deploying Frappe HR in production environments with enterprise-grade security and performance optimization.

Server Requirements

Minimum Specifications

  • CPU 2 cores
  • RAM 4GB
  • Storage 50GB SSD
  • OS Ubuntu 22.04 LTS

Recommended Specifications

  • CPU 4 cores
  • RAM 8GB
  • Storage 100GB SSD
  • Network Public IP

Cloud Provider Options

This setup is compatible with any VPS provider. Recommended services include:

DigitalOcean
From $24/month
Linode
From $24/month
Vultr
From $24/month
AWS EC2
t3.medium
Google Cloud
e2-medium
Hetzner
CX31

Server Setup and Connection

SSH Key Authentication (Recommended)

# Connect using SSH key
ssh root@YOUR_SERVER_IP -i /path/to/your/private/key

Password Authentication

# Connect using password
ssh root@YOUR_SERVER_IP
# Enter password when prompted

Initial Security Setup

# Update root password
passwd

# Create sudo user
adduser admin
usermod -aG sudo admin

# Switch to new user
su - admin

System Preparation

Update System Packages

# Update package lists and upgrade system
sudo apt-get update && sudo apt-get upgrade -y

# Install essential utilities
sudo apt-get install -y ca-certificates curl git wget \
  software-properties-common apt-transport-https \
  lsb-release gnupg

What this does: Updates your system to the latest security patches and installs basic tools needed for the installation process.

Docker Installation

Add Docker Repository

# Create directory for Docker GPG key
sudo install -m 0755 -d /etc/apt/keyrings

# Download and add Docker's official GPG key
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add Docker repository to sources
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Update package lists with Docker repository
sudo apt-get update

What this does: Adds Docker's official repository to your system so you can install the latest stable version.

Install Docker Engine

# Install Docker Engine and Compose plugin
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

# Add current user to docker group
sudo usermod -aG docker $USER

# Apply group changes
newgrp docker

Verify Installation

# Check Docker version
docker --version

# Check Docker Compose version
docker compose version

# Test Docker installation
docker run --rm hello-world

Expected output: You should see version numbers and a "Hello from Docker!" message.

Frappe HR Installation

Clone Repository

# Clone the official Frappe HR repository
git clone https://github.com/frappe/hrms

# Navigate to Docker directory
cd hrms/docker

Deploy Frappe HR

# Start all services in background
docker compose up -d

# Monitor the installation process (optional)
docker compose logs -f

What this does: Downloads and starts MariaDB, Redis, and Frappe application. Creates initial site and database. This process takes 5-15 minutes depending on your server speed.

Verify Installation

# Check running containers
docker ps

# Test local access
curl http://localhost:8000

Default login credentials:
Username: Administrator
Password: admin

Domain and DNS Configuration

Direct DNS Setup (Simple)

If you're managing DNS directly without a proxy:

# A Record Configuration
Type: A
Name: @ (or your subdomain)
Value: YOUR_SERVER_IP
TTL: 300

# CNAME Record (for subdomains)
Type: CNAME
Name: hr (or your chosen subdomain)
Value: yourdomain.com
TTL: 300

Cloudflare Proxy Setup (Recommended)

For additional security and performance:

# Cloudflare A Record
Type: A
Name: @ (or subdomain like 'hr')
Value: YOUR_SERVER_IP
Proxy status: Proxied (orange cloud)

# SSL/TLS Setting
SSL/TLS → Overview → Full (Strict)

# Origin Certificate
SSL/TLS → Origin Server → Create Certificate

Nginx Reverse Proxy Setup

Install Nginx

# Install Nginx web server
sudo apt install nginx -y

# Start and enable Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

Create Nginx Configuration

# Create configuration file
sudo nano /etc/nginx/sites-available/your-domain.com

Configuration content for Direct DNS:

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;
    
    # Security headers
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    
    # Logging
    access_log /var/log/nginx/your-domain.access.log;
    error_log /var/log/nginx/your-domain.error.log;
    
    # Proxy to Frappe HR
    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
        
        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        # Buffering
        proxy_buffering on;
        proxy_buffer_size 8k;
        proxy_buffers 8 8k;
    }
    
    # Static files optimization
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Enable Configuration

# Create symbolic link to enable site
sudo ln -s /etc/nginx/sites-available/your-domain.com /etc/nginx/sites-enabled/

# Remove default configuration
sudo rm /etc/nginx/sites-enabled/default

# Test configuration
sudo nginx -t

# Restart Nginx
sudo systemctl restart nginx

SSL Certificate Configuration

Install Certbot

# Install Snapd
sudo apt install snapd -y

# Install Certbot via Snap
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot

# Create symbolic link
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Obtain SSL Certificate

# Obtain certificate and automatically configure Nginx
sudo certbot --nginx -d your-domain.com -d www.your-domain.com

# Follow the prompts:
# 1. Enter email address
# 2. Agree to Terms of Service
# 3. Choose whether to share email with EFF
# 4. Select redirect option (recommended: 2 - Redirect HTTP to HTTPS)

Verify SSL Configuration

# Test certificate renewal
sudo certbot renew --dry-run

# Check certificate status
sudo certbot certificates

Firewall Configuration

Install and Configure UFW

# Install UFW (Ubuntu Firewall)
sudo apt install ufw -y

# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH (CRITICAL - do this first!)
sudo ufw allow 22/tcp

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

# Enable firewall
sudo ufw enable

# Check status
sudo ufw status verbose

Critical: Always allow SSH before enabling the firewall to avoid being locked out of your server.

Block Direct Access to Docker Ports

# Block direct access to application ports
sudo iptables -I DOCKER-USER -i eth0 -p tcp --dport 8000 -s ! 127.0.0.1 -j DROP
sudo iptables -I DOCKER-USER -i eth0 -p tcp --dport 3306 -s ! 127.0.0.1 -j DROP
sudo iptables -I DOCKER-USER -i eth0 -p tcp --dport 6379 -s ! 127.0.0.1 -j DROP

# Install iptables-persistent to save rules
sudo apt install iptables-persistent -y

# Save current rules
sudo netfilter-persistent save

Security Hardening

Configure SSH Security

# Edit SSH configuration
sudo nano /etc/ssh/sshd_config

# Find and modify these lines:
# PermitRootLogin no
# PasswordAuthentication no  # Only if using SSH keys
# PubkeyAuthentication yes

# Restart SSH service
sudo systemctl restart sshd

Set Up Automatic Security Updates

# Install unattended-upgrades
sudo apt install unattended-upgrades -y

# Configure automatic updates
sudo dpkg-reconfigure -plow unattended-upgrades

Set Up Fail2Ban (Optional)

# Install Fail2Ban
sudo apt install fail2ban -y

# Create local configuration
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# Edit configuration
sudo nano /etc/fail2ban/jail.local

# Find [sshd] section and ensure:
# enabled = true
# port = 22
# maxretry = 3
# bantime = 3600

# Restart Fail2Ban
sudo systemctl restart fail2ban
sudo systemctl enable fail2ban

User Management

Create Additional Users

# Access Frappe container
docker exec -it docker-frappe-1 bash

# Create new user
bench --site hrms.localhost add-user user@yourdomain.com \
  --first-name First --last-name Last \
  --password SecurePassword123

# Available roles:
# - System Manager (full admin)
# - HR Manager (HR operations)
# - HR User (basic HR functions)
# - Employee (self-service)

# Assign role
bench --site hrms.localhost set-user-role user@yourdomain.com "HR Manager"

# Exit container
exit

Create Demo User

# Access Frappe container
docker exec -it docker-frappe-1 bash

# Create demo user
bench --site hrms.localhost add-user demo@yourdomain.com \
  --first-name Demo --last-name User \
  --password DemoPassword123 --send-welcome-email 0

# Assign roles
bench --site hrms.localhost set-user-role demo@yourdomain.com "HR Manager"
bench --site hrms.localhost set-user-role demo@yourdomain.com "Employee"

# Exit container
exit

Monitoring and Maintenance

Set Up Automatic Certificate Renewal

# Add cron job for certificate renewal
sudo crontab -e

# Add this line:
0 2 * * 1 /usr/bin/certbot renew --quiet && /bin/systemctl reload nginx

Monitor System Resources

# Install monitoring tools
sudo apt install htop iotop nethogs -y

# Check system resources
htop

# Monitor disk usage
df -h

# Check Docker container status
docker ps
docker stats

# View application logs
docker logs docker-frappe-1

Automated Backup Script

# Create backup script
sudo nano /usr/local/bin/backup-frappe.sh

# Add content:
#!/bin/bash
BACKUP_DIR="/backup/frappe"
DATE=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup database
docker exec docker-mariadb-1 mysqldump -u root -padmin --all-databases > $BACKUP_DIR/database_$DATE.sql

# Backup sites directory
docker cp docker-frappe-1:/home/frappe/frappe-bench/sites $BACKUP_DIR/sites_$DATE

# Compress backups
tar -czf $BACKUP_DIR/frappe_backup_$DATE.tar.gz $BACKUP_DIR/database_$DATE.sql $BACKUP_DIR/sites_$DATE

# Remove uncompressed backups
rm -rf $BACKUP_DIR/database_$DATE.sql $BACKUP_DIR/sites_$DATE

# Keep only last 7 days of backups
find $BACKUP_DIR -name "frappe_backup_*.tar.gz" -mtime +7 -delete

echo "Backup completed: frappe_backup_$DATE.tar.gz"
# Make script executable
sudo chmod +x /usr/local/bin/backup-frappe.sh

# Add to cron for daily backups
sudo crontab -e

# Add line:
0 3 * * * /usr/local/bin/backup-frappe.sh

Useful Maintenance Commands

# Restart all services
sudo systemctl restart nginx
docker restart docker-frappe-1 docker-mariadb-1 docker-redis-1

# Update system packages
sudo apt update && sudo apt upgrade -y

# Update Docker containers
cd ~/hrms/docker
docker compose pull
docker compose up -d

# Check disk space
df -h
du -sh /var/lib/docker/

# Clean up Docker
docker system prune -f

Final Security Checklist

Before going live, ensure you have completed:

  • Changed default passwords
  • Configured firewall (UFW)
  • Set up SSL certificate
  • Configured real IP detection (if using Cloudflare)
  • Set up automatic security updates
  • Configured log rotation
  • Set up automated backups
  • Tested certificate renewal
  • Disabled unnecessary services
  • Set up monitoring
  • Documented your configuration

Production Ready: This deployment is now production-ready with enterprise-grade security, SSL encryption, firewall protection, and monitoring capabilities. Regular maintenance and updates are essential for continued security and performance.