#!/bin/bash
echo "DO NOT USE A PERIOD IN THE DATABASE NAME"
echo "use an underscore in place of a period"
echo "What is your domain name?"
read domain
DB="$domain"
create random database user
DBUSER="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 12 | head -n 1)"
create random password
PASSWORD="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 12 | head -n 1)"
create random database prefix
PREFIX="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 4 | head -n 1)"
mysql <
angelscript
⚠️ Important Security Notes:
- The script generates random credentials for enhanced security
- Database usernames and passwords are 12 characters long
- Save these credentials immediately - they cannot be recovered
- Never use periods in database names; use underscores instead
Script 3: Generate Admin Credentials
nano 3.admin_credentials.sh
#!/bin/bash
Generate and display WordPress admin username and password
echo "Randomly Generated 30 Character WordPress Administrative Credentials"
echo ""
echo "WordPress Admin Username: $(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 30 | head
-n 1)"
echo "WordPress Admin Password: $(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 30 | head
-n 1)"
Fetch WordPress salts
wp_salts=$(curl -s https://api.wordpress.org/secret-key/1.1/salt/)
Add WP constants
wp_constants=$(cat << 'EOF' /** Allow Direct Updating Without FTP /
define('FS_METHOD', 'direct' ); /* Disable Editing of Themes and Plugins Using the Built
In Editor / define('DISALLOW_FILE_EDIT', 'true' ); /* TURN OFF AUTOMATIC UPDATES */
define('WP_AUTO_UPDATE_CORE', 'false' ); EOF ) Output the salts and constants echo ""
echo "WordPress Salts" echo "" echo "$wp_salts" echo ""
echo "Constants to be added to wp-config.php" echo "" echo "$wp_constants"
angelscript
💡 Script Features:
- Generates 30-character admin credentials for maximum security
- Retrieves fresh WordPress salts from official API
- Provides security constants for wp-config.php
- Disables file editing through WordPress admin panel
Script 4: NGINX Server Block Configuration
nano 4.nginx_server_block.sh
#!/bin/bash
Function to create directories and files if they don't exist
create_files_and_directories() {
# Check if the includes directory exists, if not create it
if [ ! -d "/etc/nginx/includes" ]; then
sudo mkdir -p /etc/nginx/includes
fi
# Check if fastcgi_optimize.conf exists, if not create it
if [ ! -f "/etc/nginx/includes/fastcgi_optimize.conf" ]; then
sudo tee /etc/nginx/includes/fastcgi_optimize.conf > /dev/null <<EOF
fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 512k;
fastcgi_buffers 512 16k;
fastcgi_busy_buffers_size 1m;
fastcgi_temp_file_write_size 4m;
fastcgi_max_temp_file_size 4m;
fastcgi_intercept_errors on;
EOF
fi
# Check if browser_caching.conf exists, if not create it
if [ ! -f "/etc/nginx/includes/browser_caching.conf" ]; then
sudo tee /etc/nginx/includes/browser_caching.conf > /dev/null <<EOF
location ~*
.(webp|3gp|gif|jpg|jpeg|png|ico|wmv|avi|asf|asx|mpg|mpeg|mp4|pls|mp3|mid|wav|swf|flv|exe|zip|tar|rar|gz|tgz|bz2|uha|7z|doc|docx|xls|xlsx|pdf|iso)$
{
add_header Cache-Control "public, no-transform";
access_log off;
expires 365d;
}
location ~* .(js)$ {
add_header Cache-Control "public, no-transform";
access_log off;
expires 30d;
}
location ~* .(css)$ {
add_header Cache-Control "public, no-transform";
access_log off;
expires 30d;
}
location ~* .(eot|svg|ttf|woff|woff2)$ {
add_header Cache-Control "public, no-transform";
access_log off;
expires 30d;
}
EOF
fi
}
Function to create domain.com.conf file
create_domain_conf_file() {
domain=$1
filename="/etc/nginx/sites-available/$domain.conf"
perl
# Define server_name without checking for subdomain
server_name="$domain www.$domain"
# Check if the domain.com.conf file exists, if not create it
if [ ! -f "$filename" ]; then
sudo tee "$filename" > /dev/null <<EOF
server {
awk
listen 80;
server_name $server_name;
root /var/www/$domain/public_html;
index index.php;
location / {
try_files \$uri \$uri/ /index.php\$is_args\$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
include /etc/nginx/includes/fastcgi_optimize.conf;
}
include /etc/nginx/includes/browser_caching.conf;
access_log /var/log/nginx/access_$domain.log combined buffer=256k flush=60m;
error_log /var/log/nginx/error_$domain.log;
}
EOF
fi
awk
# Create a symbolic link to the sites-enabled directory
sudo ln -s /etc/nginx/sites-available/$domain.conf /etc/nginx/sites-enabled/
}
Main script starts here
Ask for domain name
read -p "Enter domain name: " domain_name
Call function to create directories and files
create_files_and_directories
Call function to create domain.com.conf file
create_domain_conf_file "$domain_name"
Display success message
echo "Configuration files created successfully."
angelscript
✅ After Running This Script:
- NGINX server block configuration is created
- FastCGI optimization settings are applied
- Browser caching rules are configured
- Access and error logs are set up
Validate NGINX Configuration
Always test your NGINX configuration before reloading:
sudo nginx -t
sudo systemctl reload nginx
🌐 WordPress Installation
Download WordPress
cd
wget https://wordpress.org/latest.tar.gz
ls
Extract and Configure
tar xf latest.tar.gz
ls
cd wordpress/
ls
mv wp-config-sample.php wp-config.php
ls
Edit Configuration File
nano wp-config.php
💡 Configuration Changes Required:
- Database Name: Enter the database name from script 2
- Database User: Enter the generated username
- Database Password: Enter the generated password
- Salts: Replace with salts from script 3
- Table Prefix: Use the generated prefix (e.g., abc1_)
- WP Constants: Add security constants from script 3
Deploy WordPress Files
cd
rsync -artv wordpress/ /var/www/example.com/public_html/
cd /var/www/example.com/
sudo chown -R www-data:www-data public_html/
ls -l
cd public_html/
ls -l
✅ Next Step: Complete the WordPress installation through your web browser by
navigating to your domain name.
🔒 WordPress Hardening
Security Hardening Components
1
PHP-FPM Pools
Isolate each site with dedicated PHP pools
2
File Permissions
Restrict access to critical files
3
Database Security
Limit database privileges
4
SSL/TLS
Encrypt all communications
PHP-FPM Pool Configuration
Create Dedicated User
sudo useradd username
sudo usermod -a -G username www-data
sudo usermod -a -G www-data username
sudo usermod -a -G $USER username
Create Pool Configuration
cd /etc/php/8.3/fpm/pool.d/
ls
sudo cp www.conf example.com.conf
ls
sudo nano example.com.conf
; pool name
[example]
; Username and Group
user = username
group = username
; Path and Unix Socket Filename - unique to this pool
listen = /run/php/php8.3-fpm-example.com.sock
; Set open file descriptor rlimit.
rlimit_files = 15000
; Set max core size rlimit.
rlimit_core = 100
; PHP POOL CONFIGURATION
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/fpm-php.example.log
php_admin_flag[log_errors] = on
angelscript
Create Log File
sudo touch /var/log/fpm-php.example.log
sudo chown username:www-data /var/log/fpm-php.example.log
sudo chmod 660 /var/log/fpm-php.example.log
Update NGINX Configuration
sudo grep "listen = /" example.com.conf
sudo nano /etc/nginx/sites-available/example.com.conf
Modify the fastcgi_pass directive:
fastcgi_pass unix:/run/php/php8.3-fpm-example.com.sock;
Test and Reload Services
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl reload php8.3-fpm
File Ownership and Permissions
Standard Permissions (for updates)
cd /var/www/example.com/
ls -l
sudo chown -R username:username public_html/ tmp/
sudo chmod 770 public_html/
sudo chmod 770 tmp/
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 {}
\;
ls -l
Hardened Permissions (production)
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 {} \;
⚠️ Permission Levels:
| Mode |
Directories |
Files |
Usage |
| Standard |
770 |
660 |
When updating WordPress, themes, or plugins |
| Hardened |
550 |
440 |
Production mode - maximum security |
| wp-content |
770 |
660 |
Always writable for uploads and cache |
PHP Function Restrictions
Add to your PHP pool configuration file:
; ENABLED FUNCTIONS
; disk_free_space
; DISABLED FUNCTIONS
php_admin_value[disable_functions] = shell_exec, opcache_get_configuration, opcache_get_status,
disk_total_space, diskfreespace, dl, exec, passthru, pclose, pcntl_alarm, pcntl_exec, pcntl_fork,
pcntl_get_last_error, pcntl_getpriority, pcntl_setpriority, pcntl_signal, pcntl_signal_dispatch,
pcntl_sigprocmask, pcntl_sigtimedwait, pcntl_sigwaitinfo, pcntl_strerror, pcntl_waitpid, pcntl_wait,
pcntl_wexitstatus, pcntl_wifcontinued, pcntl_wifexited, pcntl_wifsignaled, pcntl_wifstopped,
pcntl_wstopsig, pcntl_wtermsig, popen, posix_getpwuid, posix_kill, posix_mkfifo, posix_setpgid,
posix_setsid, posix_setuid, posix_uname, proc_close, proc_get_status, proc_nice, proc_open,
proc_terminate, show_source, system
angelscript
sudo systemctl reload php8.3-fpm
Open Base Directory Restrictions
cd /etc/php/8.3/fpm/pool.d/
sudo nano example.com.conf
php_admin_value[upload_tmp_dir] = /var/www/example.com/tmp/
php_admin_value[sys_temp_dir] = /var/www/example.com/tmp/
php_admin_value[open_basedir] = /var/www/example.com/public_html/:/var/www/example.com/tmp/
angelscript
SSL/TLS Certificate Installation
sudo certbot certonly --webroot -w /var/www/example.com/public_html/ -d
example.com -d www.example.com
Create SSL Configuration File
sudo nano /etc/nginx/ssl/ssl_certs_example.com.conf
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
SSL STAPLING
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
pgsql
Update Server Block for HTTPS
server {
listen 80;
server_name example.com www.example.com;
# ADD REDIRECT TO HTTPS: 301 PERMANENT 302 TEMPORARY
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
http2 on;
awk
listen 443 quic;
http3 on;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
index index.php;
# ADD SITE AND ALL SSL INCLUDE FILES
include /etc/nginx/ssl/ssl_certs_example.com.conf;
include /etc/nginx/ssl/ssl_all_sites.conf;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# Place ABOVE the php processing location block
include /etc/nginx/includes/http_headers.conf;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_param HTTP_HOST $host;
fastcgi_pass unix:/run/php/php8.3-fpm-example.com.sock;
include /etc/nginx/includes/fastcgi_optimize.conf;
}
include /etc/nginx/includes/browser_caching.conf;
access_log /var/log/nginx/access_example.com.log combined buffer=256k flush=60m;
error_log /var/log/nginx/error_example.com.log;
}
angelscript
sudo nginx -t
sudo systemctl reload nginx
Verify SSL Configuration
curl -I http://example.com
curl -I http://www.example.com
curl -I https://www.example.com
curl -I https://example.com
💡 Test Your SSL Certificate:
Rate Limiting
cd /etc/nginx/includes/
sudo cp rate_limiting_example.com.conf
rate_limiting_example.net.conf
sudo nano rate_limiting_example.net.conf
location = /wp-login.php {
limit_req zone=wp burst=20 nodelay;
limit_req_status 444;
include snippets/fastcgi-php.conf;
fastcgi_param HTTP_HOST $host;
fastcgi_pass unix:/run/php/php8.3-fpm-example.com.sock;
include /etc/nginx/includes/fastcgi_optimize.conf;
}
location = /xmlrpc.php {
limit_req zone=wp burst=20 nodelay;
limit_req_status 444;
include snippets/fastcgi-php.conf;
fastcgi_param HTTP_HOST $host;
fastcgi_pass unix:/run/php/php8.3-fpm-example.com.sock;
include /etc/nginx/includes/fastcgi_optimize.conf;
}
Add to your NGINX server block:
# Rate Limiting Include
include /etc/nginx/includes/rate_limiting_example.net.conf;
angelscript
Database Privilege Restriction
Verify Database Credentials
sudo grep DB_NAME /var/www/example.com/public_html/wp-config.php
sudo grep DB_USER /var/www/example.com/public_html/wp-config.php
Restrict Privileges
REVOKE ALL PRIVILEGES ON database_name.* FROM 'username'@'localhost';
GRANT SELECT, INSERT, UPDATE, DELETE ON database_name.* TO 'username'@'localhost';
FLUSH PRIVILEGES;
angelscript
⚠️ Database Security Note:
Restricting privileges prevents the database user from performing dangerous operations like DROP,
ALTER, or CREATE. This limits damage from SQL injection attacks.
⚡ Performance Optimization
Optimization Stack
1
WordPress Config
Post revisions, memory limits, cron
2
OPcache
PHP bytecode caching
3
FastCGI Cache
Full-page caching
4
HTTP/3 & QUIC
Modern protocols
WordPress Configuration Optimizations
Disable Post Revisions
Add to wp-config.php:
define('WP_POST_REVISIONS', false);
Increase Memory Limit
Edit PHP pool configuration:
cd /etc/php/8.3/fpm/pool.d/
sudo nano example.com.conf
php_admin_value[memory_limit] = 256M
Add to wp-config.php:
/** MEMORY LIMIT */
define('WP_MEMORY_LIMIT', '256M');
routeros
Optimize WordPress Cron
Add to wp-config.php:
/** DISABLE WP-CRON */
define('DISABLE_WP_CRON', true);
angelscript
Setup system cron job:
crontab -e
*/15 * * * * wget -q -O - https://example.com/wp-cron.php?doing_wp_cron
>/dev/null 2>&1
OPcache Configuration
cd /etc/php/8.3/fpm/pool.d/
sudo nano example.com.conf
Development Server Configuration
; OPCACHE CONFIGURATION - DEVELOPMENT SERVER - Jul 2025
; Directive php_admin_flag[opcache.enabled] leave commented - enabled by default
; php_admin_flag[opcache.enabled] = 1
php_admin_value[opcache.memory_consumption] = 256
php_admin_value[opcache.interned_strings_buffer] = 32
php_admin_value[opcache.max_accelerated_files] = 20000
php_admin_flag[opcache.validate_timestamps] = 1
php_admin_value[opcache.revalidate_freq] = 2
php_admin_flag[opcache.validate_permission] = 1
Production Server Configuration
; OPCACHE CONFIGURATION - PRODUCTION SERVER - Jul 2025
; Directive php_admin_flag[opcache.enabled] leave commented - enabled by default
;php_admin_flag[opcache.enabled] = 1
;php_admin_value[opcache.memory_consumption] = 256
;php_admin_value[opcache.interned_strings_buffer] = 32
;php_admin_value[opcache.max_accelerated_files] = 20000
;php_admin_flag[opcache.validate_timestamps] = 0
;php_admin_flag[opcache.validate_permission] = 1
angelscript
💡 OPcache Settings Explained:
| Setting |
Value |
Description |
| memory_consumption |
256 MB |
Memory allocated for OPcache |
| interned_strings_buffer |
32 MB |
Memory for interned strings |
| max_accelerated_files |
20000 |
Maximum number of cached files |
| validate_timestamps |
0 (prod) / 1 (dev) |
Check for file changes |
| revalidate_freq |
2 seconds |
How often to check timestamps |
Permission Management Scripts
Script 5: Loosen Permissions (for updates)
cd
cd wp_bash_scripts/
nano 5.loosen_permissions.sh
#!/bin/bash
List directory contents of /var/www for reference
sudo ls -l /var/www
Prompt for the domain name
read -p "Enter the domain name: " domain_name
Check if the domain directory exists
if [ ! -d "/var/www/$domain_name/public_html/" ]; then
echo "Error: Domain directory /var/www/$domain_name/public_html/ does not exist."
exit 1
fi
Set permissions with confirmation
echo "Setting permissions for /var/www/$domain_name/public_html/..."
Grant read, write, and execute permissions to owner and group - directories
sudo find "/var/www/$domain_name/public_html/" -type d -exec chmod 770 {} ;
Grant read and write permissions to owner and group - files
sudo find "/var/www/$domain_name/public_html/" -type f -exec chmod 660 {} ;
echo "Permissions set to allow WordPress updates using the dashboard!"
angelscript
Script 6: Tighten Permissions (production mode)
cd
cd wp_bash_scripts/
nano 6.tighten_permissions.sh
#!/bin/bash
List directory contents of /var/www for reference
sudo ls -l /var/www
Prompt for the domain name
read -p "Enter the domain name: " domain_name
Check if the domain directory exists
if [ ! -d "/var/www/$domain_name/public_html/" ]; then
echo "Error: Domain directory /var/www/$domain_name/public_html/ does not exist."
exit 1
fi
Set permissions with confirmation
echo "Setting permissions for /var/www/$domain_name/public_html/..."
Grant read and execute permissions to the owner and group only
sudo find "/var/www/$domain_name/public_html/" -type d -exec chmod 550 {} ;
Grant read permissions to the owner and group only
sudo find "/var/www/$domain_name/public_html/" -type f -exec chmod 440 {} ;
Grant read, write and execute permissions to the owner and group only - wp-content/
sudo find "/var/www/$domain_name/public_html/wp-content" -type d -exec chmod 770 {} ;
Grant read, write to the owner and group only - wp-content/
sudo find "/var/www/$domain_name/public_html/wp-content/" -type f -exec chmod 660 {} ;
echo "Permissions hardened, no write permissions on core WordPress files and directories!"
angelscript
FastCGI Caching
Configure nginx.conf
cd /etc/nginx
sudo nano nginx.conf
### FASTCGI CACHING
fastcgi_cache_path directive - PATH & NAME must be unique for each site
Add a new fastcgi_cache_path for each site and give a new keys_zone name
fastcgi_cache_path /var/run/SITE levels=1:2 keys_zone=NAME:100m inactive=60m;
fastcgi_cache_path /var/run/SITE2 levels=1:2 keys_zone=NAME2:100m inactive=60m;
applied to all sites
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
angelscript
Update Server Block
cd /etc/nginx/sites-available/
sudo nano example.com.conf
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_param HTTP_HOST $host;
fastcgi_pass unix:/run/php/php8.3-fpm-example.com.sock;
include /etc/nginx/includes/fastcgi_optimize.conf;
# fastcgi caching directives
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache NAME;
fastcgi_cache_valid 60m;
}
include /etc/nginx/includes/fastcgi_cache_excludes.conf;
add_header X-FastCGI-Cache $upstream_cache_status;
Cache purge endpoint
location ~ /purge(/.*) {
fastcgi_cache_purge NAME "$scheme$request_method$host$1";
}
angelscript
✅ FastCGI Cache Benefits:
- Dramatically reduces server load
- Serves cached pages in microseconds
- Reduces database queries
- Improves response time for visitors
📊 Monitoring & Maintenance
PHP-FPM Pool Memory Usage
cd ~/wp_bash_scripts/
nano pool_list_usage.sh
#!/bin/bash
Extract pool names
pools=$(grep -E '^\suser\s=' /etc/php/8.3/fpm/pool.d/*.conf | awk -F= '{print $2}' | xargs | tr ' '
'\n' | sort -u)
Display memory used by each pool
for pool in $pools; do
memory_used=$(ps -C php-fpm --user "$pool" -o rss= | awk '{ sum += $1; count++ } END { if (count >
0) printf ("%d%s\n", sum/NR/1024,"M") }')
echo -e "Pool: $pool\nMemory Used: $memory_used\n"
done
angelscript
OPcache File Count Monitoring
nano opcache_files.sh
#!/bin/bash
echo ""
echo "Checking for and displaying the opcache.max_accelerated_files directive value in each sites
PHP pool file"
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 ' ')
echo "File: $filename - opcache.max_accelerated_files: $value"
else
echo "File: $filename - opcache.max_accelerated_files directive not found"
fi
done
echo ""
echo "Listing sites and number of PHP files in each site, compare to the value set in the pool file"
echo ""
WWW_DIR="/var/www/"
for domain_dir in "$WWW_DIR"*/ ; do
if [ "$domain_dir" == "/var/www/html/" ]; then
continue
fi
routeros
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 "Domain: $domain_name - PHP files: $php_file_count"
else
echo "Domain: $domain_name - public_html directory not found"
fi
done
echo ""
angelscript
⚠️ OPcache Max Accelerated Files:
The directive value of 20,000 actually represents 32,000 files due to how PHP calculates the
nearest prime number. Always ensure the number of PHP files in your site is lower than this
value for optimal performance.
- Run this script monthly to monitor file counts
- If a site approaches 15,000-16,000 files, increase the max_accelerated_files value
- Restart PHP-FPM after making changes
Example Output
Checking for and displaying the opcache.max_accelerated_files directive value in
each sites PHP pool file
File: expert.wp.help.conf - opcache.max_accelerated_files: 20000
File: nginx.help.conf - opcache.max_accelerated_files: 20000
File: www.conf - opcache.max_accelerated_files directive not found
Listing sites and number of PHP files in each site, compare to the value set in the pool file
Domain: expert.wp.help - PHP files: 1432
Domain: nginx.help - PHP files: 1575
angelscript
Maintenance Best Practices
💡 Regular Maintenance Tasks:
- Weekly: Review error logs, monitor resource usage
- Monthly: Run OPcache file count script, check for WordPress updates
- Quarterly: Review and optimize database, check SSL certificate expiration
- Semi-annually: Security audit, performance benchmarking
Maintenance Workflow
Loosen Permissions
↓
Update WordPress/Plugins/Themes
↓
Test Functionality
↓
Tighten Permissions
↓
Clear Caches
↓
Monitor Performance
📝 Quick Reference Commands
| Task |
Command |
| Test NGINX config |
sudo nginx -t |
| Reload NGINX |
sudo systemctl reload nginx |
| Reload PHP-FPM |
sudo systemctl reload php8.3-fpm |
| Check NGINX status |
sudo systemctl status nginx |
| View NGINX error log |
sudo tail -f /var/log/nginx/error.log |
| View site-specific error log |
sudo tail -f /var/log/nginx/error_example.com.log |
| List PHP pools |
ls /etc/php/8.3/fpm/pool.d/ |
| Check file ownership |
ls -l /var/www/example.com/ |
| Generate SSL cert |
sudo certbot certonly --webroot |
| Renew SSL certs |
sudo certbot renew |
🎯 Summary
This guide has covered the complete process of adding and securing additional WordPress sites on your
NGINX server. By following these steps, you've implemented:
✅ Automation
Bash scripts for consistent deployments
🔒 Security
Isolated PHP pools, restricted permissions, SSL/TLS
⚡ Performance
OPcache, FastCGI caching, HTTP/3
📊 Monitoring
Scripts for ongoing maintenance
✅ You're Ready!
Your server is now configured to host multiple WordPress sites with enterprise-level security and
performance. Remember to run the maintenance scripts regularly and keep all software updated.