1. System Updates
Keeping your Ubuntu server updated is critical for security and stability. This section covers three
methods to update your system: manual commands, bash aliases, and automated scripts.
1.1 Manual Update Commands
đ Best Practice: Run system updates weekly or after critical security patches are
released.
Step 1: Update package lists
sudo apt update
Step 2: Upgrade installed packages
sudo apt upgrade
Step 3: Remove unnecessary packages
sudo apt autoremove
Update Process Flow
apt update
â
apt upgrade
â
apt autoremove
â
â Complete
1.2 Combined Command (One-Line Execution)
Without automatic confirmation:
sudo apt update && sudo apt upgrade && sudo apt autoremove
With automatic confirmation (-y flag):
sudo apt update && sudo apt upgrade -y && sudo apt autoremove -y
1.3 Creating a Bash Alias
Aliases allow you to create shortcuts for frequently used commands. This saves time and reduces
typing errors.
1
Open the bash aliases file:
cd
nano .bash_aliases
2
Add the alias:
alias server_updates='sudo apt update && sudo apt upgrade -y && sudo apt
autoremove -y'
3
Activate the alias:
exit
After logging back in, you can run: server_updates
1.4 Creating an Automated Script
Scripts provide more control and can include error checking and logging.
1
Create the script file:
sudo nano server_updates.sh
2
Add the following content:
#!/bin/bash
# Check if script is run as root
if [ "$EUID" -ne 0 ]; then
echo "Please run this script with sudo or as root."
exit
fi
# Update package lists
echo "Updating package lists..."
sudo apt update
# Upgrade installed packages
echo "Upgrading installed packages..."
sudo apt upgrade
# Remove unnecessary packages
echo "Removing unnecessary packages..."
sudo apt autoremove
echo "Update, upgrade, and autoremove completed."
3
Make the script executable:
sudo chmod +x server_updates.sh
4
Run the script:
sudo ./server_updates.sh
â ī¸ Note: The script removes the -y flags to allow manual review of
updates before installation.
2. WordPress Updates & Permissions
Proper file permissions are crucial for WordPress security and functionality. This section covers two
permission strategies: default permissions for updates and hardened permissions for production.
2.1 Default PHP Pool User Permissions (For Updates)
These permissions allow WordPress to update plugins, themes, and core files through the dashboard.
1
Navigate to the website directory:
cd /var/www/example.com/
2
Check current permissions:
sudo ls -l public_html/
3
Set ownership to PHP pool user:
sudo chown -R PHP_POOL_USER:PHP_POOL_USER public_html/
4
Set directory permissions (770):
sudo find /var/www/example.com/public_html/ -type d -exec chmod 770 {} \;
5
Set file permissions (660):
sudo find /var/www/example.com/public_html/ -type f -exec chmod 660 {} \;
â Result: Open the WordPress Dashboard and all updates will run without issues.
6
Restart PHP-FPM:
sudo systemctl reload php8.3-fpm
2.2 File Permission Breakdown
| Permission |
Numeric |
Description |
Use Case |
| 770 |
rwxrwx--- |
Owner & Group: full access |
Directories (update mode) |
| 660 |
rw-rw---- |
Owner & Group: read/write |
Files (update mode) |
| 550 |
r-xr-x--- |
Owner & Group: read/execute |
Directories (hardened) |
| 440 |
r--r----- |
Owner & Group: read only |
Files (hardened) |
2.3 Hardened Permissions (For Production)
After updates are complete, harden permissions to protect against unauthorized modifications.
1
Navigate to website directory:
cd /var/www/example.com/
2
Check current permissions:
sudo ls -l public_html/
3
Set ownership:
sudo chown -R PHP_POOL_USER:PHP_POOL_USER public_html/
4
Harden directory permissions (550):
sudo find /var/www/example.com/public_html/ -type d -exec chmod 550 {} \;
5
Harden file permissions (440):
sudo find /var/www/example.com/public_html/ -type f -exec chmod 440 {} \;
6
Keep wp-content writable for uploads:
sudo find /var/www/example.com/public_html/wp-content/ -type d -exec chmod 770
{} \;
sudo find /var/www/example.com/public_html/wp-content/ -type f -exec chmod 660
{} \;
WordPress Update Workflow
Loosen Permissions (770/660)
â
Run WordPress Updates
â
Harden Permissions (550/440)
â
Restart PHP-FPM
2.4 Quick Permission Change Commands
Loosen permissions before updates:
sudo find /var/www/example.com/public_html/ -type d -exec chmod 770 {} \;
sudo find /var/www/example.com/public_html/ -type f -exec chmod 660 {} \;
Harden permissions after updates:
sudo find /var/www/example.com/public_html/ -type d -exec chmod 550 {} \;
sudo find /var/www/example.com/public_html/ -type f -exec chmod 440 {} \;
sudo find /var/www/example.com/public_html/wp-content/ -type d -exec chmod 770
{} \;
sudo find /var/www/example.com/public_html/wp-content/ -type f -exec chmod 660
{} \;
3. Security Scanning
Regular security scanning helps detect malware, rootkits, and security vulnerabilities. This section
covers two essential tools: ClamAV and RKHunter.
3.1 ClamAV (Antivirus Scanner)
ClamAV is an open-source antivirus engine for detecting trojans, viruses, malware, and other
malicious threats.
Installation
1
Update package lists:
sudo apt update
2
Install ClamAV:
sudo apt install clamav
âšī¸ Note: The ClamAV virus definition database will be updated automatically after
installation.
Disable Automatic Updates
For manual control over updates, disable the automatic freshclam service:
Stop the freshclam service:
sudo systemctl stop clamav-freshclam
Disable freshclam on startup:
sudo systemctl disable clamav-freshclam
Manual Database Updates
Update virus definitions manually:
sudo freshclam
Running Manual Scans
Scan a specific directory recursively:
sudo clamscan -r /path/2/scan
Complete manual scanning workflow:
sudo freshclam
sudo clamscan -r /path/2/scan
â ī¸ Important: Always update virus definitions with freshclam before
running scans.
3.2 RKHunter (Rootkit Hunter)
RKHunter is a Unix-based tool that scans for rootkits, backdoors, and possible local exploits.
Installation & Initial Setup
1
Install RKHunter:
sudo apt install rkhunter
2
Update file properties database:
sudo rkhunter --propupd
đ What is --propupd? This command updates the file properties database, which
RKHunter uses as a baseline to detect changes in system files.
Running Security Scans
Run complete system scan (skip keypresses):
sudo rkhunter --checkall --sk
Available flags:
--sk or --skip-keypress: Skip manual key presses during scan
Viewing Scan Results
View complete log file:
sudo cat /var/log/rkhunter.log
View log with pagination:
sudo less /var/log/rkhunter.log
Disable Automatic Cron Jobs
To prevent automatic scans and maintain manual control:
Remove daily cron job:
cd /etc/cron.daily/
sudo rm rkhunter
Remove weekly cron job:
cd /etc/cron.weekly/
sudo rm rkhunter
Security Scanning Workflow
Update Definitions
â
Run ClamAV Scan
â
Run RKHunter Scan
â
Review Logs
4. Database Tuning & Monitoring
Database optimization is critical for WordPress performance. This section covers monitoring queries
and using MySQLTuner for optimization recommendations.
4.1 InnoDB Buffer Pool Monitoring
The InnoDB buffer pool is the memory area where InnoDB caches table and index data. Monitoring its
usage helps optimize memory allocation.
View actual InnoDB buffer pool memory usage:
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_bytes_data';
4.2 Database Size Analysis
View all database sizes:
SELECT table_schema AS "Database", ROUND(SUM(data_length + index_length) / 1024
/ 1024, 2) AS "Size (MB)" FROM information_schema.tables GROUP BY table_schema;
View InnoDB database sizes only:
SELECT table_schema AS "Database", SUM(data_length + index_length) / 1024 /
1024 AS "Size (MB)" FROM information_schema.tables WHERE engine = 'InnoDB' GROUP BY
table_schema;
View buffer pool usage by database:
SELECT table_schema AS "Database", SUM(data_length + index_length) / 1024 /
1024 AS "Size (MB)" FROM information_schema.tables WHERE engine = 'InnoDB' GROUP BY
table_schema;
4.3 Table I/O Statistics
Understanding which tables are accessed most frequently helps optimize query performance and indexing
strategies.
View table I/O statistics:
SELECT object_schema AS 'Database', object_name AS 'Table', COUNT_READ AS
'Reads', COUNT_WRITE AS 'Writes', SUM_TIMER_READ / 1000000000 AS 'Read Time (ms)',
SUM_TIMER_WRITE / 1000000000 AS 'Write Time (ms)' FROM
performance_schema.table_io_waits_summary_by_table ORDER BY SUM_TIMER_READ + SUM_TIMER_WRITE
DESC;
đĄ Analysis Tip: Tables with high read/write times may benefit from additional
indexes or query optimization.
4.4 MySQLTuner
MySQLTuner is a Perl script that analyzes your MySQL/MariaDB configuration and provides optimization
recommendations.
1
Navigate to MySQLTuner directory:
cd
cd MySQLTuner/
2
List directory contents:
ls -l
3
Run MySQLTuner with sudo:
sudo ./mysqltuner
â ī¸ Important: MySQLTuner must be run with sudo privileges to access MariaDB and
gather necessary statistics.
| Query Type |
Purpose |
Key Metrics |
| Buffer Pool Status |
Memory usage monitoring |
Bytes in use |
| Database Size |
Storage allocation |
Total MB per database |
| InnoDB Tables |
InnoDB-specific analysis |
InnoDB storage only |
| Table I/O Stats |
Performance bottlenecks |
Reads, writes, timing |
5. Disk Space Management
Monitoring and managing disk space is critical to prevent server crashes. Running out of disk space
can cause database corruption, application failures, and system instability.
5.1 Check Disk Space Usage
Display disk usage in human-readable format:
df -h
âšī¸ Flag Explanation: The -h flag displays sizes in human-readable
format (KB, MB, GB) instead of bytes.
5.2 Clean Up Package Cache
Remove unused packages and clean cache:
sudo apt autoremove && sudo apt clean
5.3 Clean Up System Logs
System logs can accumulate quickly and consume significant disk space.
Remove logs older than 1 day:
sudo journalctl --vacuum-time=1days
â ī¸ Caution: Only remove old logs if you don't need them for troubleshooting. For
production servers, consider keeping 7-30 days of logs.
5.4 Analyze Directory Sizes
Navigate to root directory:
cd /
List directory sizes sorted by size:
du -ah --max-depth=1 | sort -h
đĄ Pro Tip: The largest directories appear at the bottom. You can navigate into any
directory and run the same command to drill down further.
Disk Space Management Workflow
Check Space (df -h)
â
Clean Packages
â
Clean Logs
â
Analyze Directories
6. NGINX Connection Backlog
The backlog parameter defines the maximum queue length for pending connections. Proper configuration
prevents connection drops during traffic spikes.
Set backlog value:
backlog=2048
HTTP configuration:
listen 80 backlog=2048;
HTTPS configuration:
listen 443 ssl backlog=2048;
đ Recommended Value: A backlog of 2048 is suitable for most production
environments. Increase this value for high-traffic sites.
7. PHP-FPM Optimization
PHP-FPM (FastCGI Process Manager) optimization is crucial for WordPress performance. This section
covers monitoring OPcache and analyzing PHP file counts.
â ī¸ Important Reminder: Setting the correct pm.max_children directive
is critical. Setting it too low or too high can significantly impact server performance. Refer to
the "Optimizing WordPress" section of the course for detailed PHP-FPM tuning guidance.
7.1 PHP-FPM Tuning Guidelines
- Single WordPress Site: Refer to the "Optimizing WordPress" section
- Multiple WordPress Sites: Refer to the "Installing Additional WordPress
Sites" section
- Tuning Frequency: Optimize PHP-FPM weekly or after significant traffic
changes
7.2 OPcache Files Monitoring Script
This script displays the number of PHP files per site and compares them with OPcache configuration
values.
1
Create the monitoring script:
nano opcache_files.sh
2
Add the script content:
#!/bin/bash
round_to_prime() {
local value=$1
primes=(223 463 983 1979 3907 7963 16229 32531 65407 130987 262237 524524 1048793)
closest=0
min_diff=$((value - primes[0]))
for prime in "${primes[@]}"; do
diff=$((value - prime))
if [ $diff -lt 0 ]; then
closest=$prime
break
elif [ $diff -lt $min_diff ]; then
min_diff=$diff
closest=$prime
fi
done
echo "$closest"
}
echo ""
echo "Checking for opcache.max_accelerated_files directive in PHP pool files..."
echo ""
echo "The value used (actual value) will be the first number in the set of prime numbers"
echo "223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793"
echo "that is greater than or equal to the configured value (value set)"
echo ""
POOL_DIR="/etc/php/8.3/fpm/pool.d/"
for file in "$POOL_DIR"*.conf; do
filename=$(basename "$file")
if grep -q "opcache.max_accelerated_files" "$file"; then
value=$(grep "opcache.max_accelerated_files" "$file" | awk -F'=' '{print $2}' | tr -d ' ')
rounded_value=$(round_to_prime "$value")
echo "File: $filename - opcache.max_accelerated_files: set value ($value) actual value
($rounded_value)"
else
echo "File: $filename - opcache.max_accelerated_files directive not found"
fi
done
echo ""
echo "Listing domain names and number of PHP files in public_html directories..."
echo ""
WWW_DIR="/var/www/"
for domain_dir in "$WWW_DIR"*/ ; do
if [ "$domain_dir" == "/var/www/html/" ]; then
continue
fi
domain_name=$(basename "$domain_dir")
public_html_dir="$domain_dir/public_html/"
if [ -d "$public_html_dir" ]; then
php_file_count=$(find "$public_html_dir" -type f -name "*.php" | wc -l)
echo "WordPress site: $domain_name - PHP files: $php_file_count"
else
echo "Domain: $domain_name - public_html directory not found"
fi
done
echo ""
3
Make the script executable:
sudo chmod +x opcache_files.sh
4
Run the script:
./opcache_files.sh
7.3 OPcache Prime Numbers Explanation
OPcache uses prime numbers for hash table sizing to reduce collisions. The system automatically
rounds up your configured value to the next available prime number.
| Prime Number |
Recommended For |
Site Type |
| 223 |
Very small sites |
Basic blogs |
| 463 |
Small sites |
Simple WordPress |
| 983 |
Small-medium sites |
Standard WordPress |
| 1979 |
Medium sites |
WordPress + plugins |
| 3907 |
Medium-large sites |
E-commerce sites |
| 7963 |
Large sites |
WooCommerce + many plugins |
| 16229+ |
Very large sites |
Enterprise WordPress |
â Best Practice: Set opcache.max_accelerated_files to the next prime
number above your total PHP file count. This ensures all files can be cached efficiently.
PHP-FPM Optimization Process
Count PHP Files
â
Round to Prime
â
Configure OPcache
â
Monitor Weekly
đ Summary & Best Practices
Key Takeaways
- Regular Updates: Run system updates weekly or after security patches
- Permission Management: Loosen permissions for updates, then harden for
production
- Security Scanning: Run ClamAV and RKHunter regularly to detect threats
- Database Optimization: Use MySQLTuner and monitor InnoDB buffer pool usage
- Disk Space: Monitor disk usage to prevent crashes
- PHP-FPM Tuning: Optimize weekly and adjust based on traffic patterns
- OPcache Configuration: Set max_accelerated_files above your PHP file count
Maintenance Schedule Recommendations
| Task |
Frequency |
Priority |
| System Updates |
Weekly |
High |
| Security Scans |
Weekly |
High |
| Disk Space Check |
Daily |
Critical |
| PHP-FPM Tuning |
Weekly |
Medium |
| Database Optimization |
Monthly |
Medium |
| Log Cleanup |
Weekly |
Low |