๐Ÿš€ NGINX Server Configuration Guide

Section 15: Complete Server Setup & Security Hardening

๐Ÿ“‹ NGINX Logs Management

NGINX logs are essential for monitoring server activity, debugging issues, and analyzing traffic patterns. All logs are stored in /var/log/nginx directory.

Accessing Log Files

cd /var/log/nginx
ls

View Complete Log File

sudo cat log_file_name.log

View Log File with Pagination

sudo less log_file_name.log
๐Ÿ’ก Pro Tip: Use less for large log files as it allows you to navigate through the file efficiently. Press 'q' to quit, 'Space' to go forward one page, and 'b' to go back one page.

๐Ÿ”ง PHP-FPM Pools Configuration

PHP-FPM pools allow you to run different PHP configurations for different websites, improving security and resource management by isolating each site.

PHP-FPM Pool Architecture

User Request
โ†’
NGINX
โ†’
PHP-FPM Pool
โ†’
PHP Script Execution

Step 1: Create System User

sudo useradd username

Step 2: Configure User Groups

Add users to appropriate groups for proper permissions:

sudo usermod -a -G username_group www-data
sudo usermod -a -G www-data username_group
sudo usermod -a -G username_group $USER

Step 3: Create PHP-FPM Pool Configuration

cd /etc/php/8.3/fpm/pool.d/
ls
sudo cp www.conf example.com.conf
sudo nano example.com.conf

Pool Configuration Example

[example]
; Unix user/group of the child processes
user = username
group = username

; The address on which to accept FastCGI requests
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 configuration flags
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/fpm-php.example.com.log
php_admin_flag[log_errors] = on

Step 4: Create FPM Log File

sudo touch /var/log/fpm-php.example.com.log
sudo chown user:www-data /var/log/fpm-php.example.com.log
sudo chmod 660 /var/log/fpm-php.example.com.log

Step 5: Reload PHP-FPM

sudo systemctl reload php8.3-fpm

Step 6: Verify Socket Configuration

sudo grep "listen = /" example.com.conf

Step 7: Update NGINX Configuration

sudo nano /etc/nginx/sites-available/example.com.conf

Add the following line in your PHP location block:

fastcgi_pass unix:/run/php/php8.3-fpm-example.com.sock;

Step 8: Test and Reload NGINX

sudo nginx -t
sudo systemctl reload nginx

Advanced PHP Pool Configuration

Set Upload and Temp Directories

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/

Create Temp Directory

cd /var/www/example.com/
sudo mkdir tmp/
sudo chown username:username tmp/
sudo chmod 770 tmp/

Configure Open Basedir (Security)

php_admin_value[open_basedir] = /var/www/example.com/public_html/:/var/www/example.com/tmp/
sudo systemctl reload php8.3-fpm

Enable/Disable PHP Functions

; Enable allow_url_fopen
php_admin_flag[allow_url_fopen] = on

; Disable dangerous 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
โš ๏ธ Important: Disabling PHP functions enhances security but may break some plugins or applications. Test thoroughly after making changes.

๐Ÿ”’ SSL/TLS Certificate Configuration

SSL certificates encrypt data between your server and visitors' browsers, ensuring secure communication. Let's Encrypt provides free SSL certificates.

Step 1: Install Certbot

sudo apt update
sudo apt install certbot python3-certbot-dns-cloudflare

Step 2: Obtain SSL Certificate

sudo certbot certonly --webroot -w /var/www/example.com/public_html/ -d example.com -d www.example.com
โœ… Success: Your certificate will be saved in /etc/letsencrypt/live/example.com/

Step 3: Generate Diffie-Hellman Parameters

cd /etc/nginx/
sudo mkdir ssl/
cd ssl/
sudo openssl dhparam -out dhparam.pem 2048
๐Ÿ’ก Note: This process may take several minutes. The DH parameters enhance SSL/TLS security.

Step 4: Create SSL Certificate Configuration

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_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

Step 5: Create Global SSL Configuration

sudo nano /etc/nginx/ssl/ssl_all_sites.conf
# CONFIGURATION RESULTS IN A+ RATING AT SSLLABS.COM
# DATE: MAY 2025

# SSL CACHING AND PROTOCOLS
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 180m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

# resolver set to Cloudflare
resolver 1.1.1.1 1.0.0.1;
resolver_timeout 15s;
ssl_session_tickets off;

# HSTS HEADERS
add_header Strict-Transport-Security "max-age=31536000;" always;

# Enable QUIC and HTTP/3
ssl_early_data on;
add_header Alt-Svc 'h3=":$server_port"; ma=86400';
add_header x-quic 'H3';
quic_retry on;
โš ๏ธ Let's Encrypt Update (May 2025): SSL stapling support was removed. The ssl_stapling directives should be commented out or removed.

Step 6: Configure NGINX Server Block for HTTPS

HTTP to HTTPS Redirect Server Block

server {
    listen 80;
    server_name example.com www.example.com;
    
    # Permanent redirect to HTTPS
    return 301 https://example.com$request_uri;
}

HTTPS Server Block (Primary Site)

server {
    listen 443 ssl;
    http2 on;
    listen 443 quic reuseport;
    http3 on;
    
    server_name example.com www.example.com;
    
    # Include SSL configurations
    include /etc/nginx/ssl/ssl_certs_example.com.conf;
    include /etc/nginx/ssl/ssl_all_sites.conf;
    
    # Rest of your configuration...
}

HTTPS Server Block (Additional Sites - No reuseport)

server {
    listen 443 ssl;
    http2 on;
    listen 443 quic;
    http3 on;
    
    server_name second-site.com www.second-site.com;
    
    # Include SSL configurations
    include /etc/nginx/ssl/ssl_certs_second-site.com.conf;
    include /etc/nginx/ssl/ssl_all_sites.conf;
    
    # Rest of your configuration...
}
๐Ÿ’ก Important: Only use reuseport on ONE server block listening on port 443 QUIC. Additional sites should omit this parameter.

Step 7: Add FastCGI Parameter for Host

In your PHP processing location block, add:

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

Step 8: Test and Reload NGINX

sudo nginx -t
sudo systemctl reload nginx

๐Ÿงช Testing HTTPS Configuration

Testing HTTP to HTTPS Redirects

Use the curl command to verify your redirects are working correctly:

curl -I http://example.com

Expected Result: 301 Moved Permanently โ†’ https://example.com

curl -I http://www.example.com

Expected Result: 301 Moved Permanently โ†’ https://example.com

curl -I https://www.example.com

Expected Result: 301 or 302 Redirect by WordPress โ†’ https://example.com

curl -I https://example.com

Expected Result: 200 OK - Site is being served

HTTPS Redirect Flow

http://example.com
โ†’
301 Redirect
โ†’
https://example.com
โ†’
200 OK

Testing SSL Certificate Grade

๐ŸŒ SSL Labs Test:
  1. Visit ssllabs.com/ssltest
  2. Select "Do not show the results on the boards" (optional)
  3. Enter your domain name
  4. Click Submit
  5. Wait for analysis to complete
Expected Result: A+ Rating

Testing HTTP/3 and QUIC Support

๐Ÿš€ HTTP/3 Check:
  1. Visit http3check.net
  2. Enter your domain name
  3. Verify QUIC and HTTP/3 support indicators

Testing HTTP/3 in Browser Developer Tools

  1. Open your website in a browser
  2. Open Developer Tools (F12 or Right-click โ†’ Inspect)
  3. Go to Network tab
  4. Right-click on column headers
  5. Ensure "Protocol" is checked
  6. Refresh the page
  7. Check the Protocol column for "h3" entries
โš ๏ธ HTTP/3 Behavior:

You may notice that the first visit uses HTTP/2, but subsequent visits or refreshes use HTTP/3. This is normal behavior because:

  • The initial connection establishes using HTTP/2 over TCP
  • The server negotiates QUIC/HTTP/3 support in the background
  • Subsequent connections use the faster HTTP/3 protocol
  • Browsers cache the fact that the server supports HTTP/3

Disable Browser Caching for Testing (Temporary)

Add this directive to your location / block ONLY for testing:

add_header Cache-Control 'no-cache,no-store';
๐Ÿšจ Important: Remove or comment out this directive after confirming HTTP/3 is working! Leaving it enabled will negatively impact your site's performance.

Updating WordPress URLs to HTTPS

After configuring HTTPS on the server, update WordPress settings:

  1. Log into WordPress Dashboard
  2. Go to Settings โ†’ General
  3. Change WordPress Address (URL) to https://example.com
  4. Change Site Address (URL) to https://example.com
  5. Click Save Changes
  6. Log in again if prompted
โš ๏ธ Mixed Content Warning:

If your WordPress URLs remain as HTTP while serving content over HTTPS, you may encounter mixed content warnings. This occurs when:

  • Some resources load over HTTP while the page is served over HTTPS
  • Browsers may block mixed content
  • Users see security warnings
  • The security benefits of HTTPS are undermined

Solution: Always update WordPress and Site addresses to HTTPS after enabling SSL certificates.

๐Ÿ” Certbot Certificate Management

Essential Certbot Commands

Command Purpose
sudo certbot certificates List all installed certificates
sudo certbot delete Delete a certificate
sudo certbot renew Renew certificates due for renewal
sudo certbot renew --dry-run Test renewal process (no actual renewal)
sudo certbot renew --force-renewal Force renewal of all certificates

List Installed Certificates

cd
sudo certbot certificates

This displays all certificates with their expiry dates and validity period.

Delete a Certificate

sudo certbot delete

Follow the interactive prompts to select which certificate to delete. Press 'C' to cancel if you change your mind.

Test Certificate Renewal

sudo certbot renew --dry-run
โš ๏ธ Always Test First: Always use --dry-run when testing renewals to avoid hitting Let's Encrypt rate limits. Repeated failed renewal attempts may temporarily block your domain.

Force Certificate Renewal

sudo certbot renew --force-renewal

This forces renewal even if certificates are not yet due for renewal.

Force Renewal with Dry Run (Testing)

sudo certbot renew --force-renewal --dry-run
โœ… Expected Output: "Congratulations! All simulated renewals succeeded."

Automated SSL Certificate Renewal with Cron

๐Ÿšจ Critical:

SSL certificate renewal is absolutely essential. Here's why:

  • Let's Encrypt certificates are valid for only 90 days
  • With HSTS headers enabled, browsers will ONLY access your site via HTTPS
  • If certificates expire, no visitors can access your site
  • You must monitor renewal success regularly

Creating Renewal Cron Jobs

We'll set up automatic renewal twice per month (14th and 28th) at 1:00 AM:

sudo crontab -e

Select nano as your editor (usually option 1).

Cron Job Configuration

# Force renewal of SSL certificates at 1:00 AM on 14th and 28th of each month
00 1 14,28 * * certbot renew --force-renewal > /dev/null 2>&1

# Reload nginx at 2:00 AM on 14th and 28th to enable new certificates
00 2 14,28 * * systemctl reload nginx > /dev/null 2>&1

Cron Schedule Explanation

Field Value Meaning
Minute 00 At minute 0
Hour 1 or 2 At 1:00 AM or 2:00 AM
Day of Month 14,28 On 14th and 28th day
Month * Every month
Day of Week * Any day of week
๐Ÿ’ก Understanding the Redirect:

> /dev/null 2>&1 explanation:

  • > - Redirect standard output
  • /dev/null - Discard output (null device)
  • 2>&1 - Redirect errors to same place as output
  • This prevents email notifications for successful cron jobs

Save and View Cron Jobs

Press Ctrl+X, then Y, then Enter to save.

sudo crontab -l

This lists all configured cron jobs.

โš ๏ธ Important Notes:
  • This cron renews ALL certificates on your server automatically
  • You don't need separate crons for each site
  • Set a reminder to check renewal success periodically
  • Run sudo certbot certificates to verify expiry dates

Verify Certificate Expiry Dates

sudo certbot certificates

This displays the expiry date and remaining validity period for all certificates.

๐Ÿ›ก๏ธ HTTP Security Headers Configuration

Security headers protect your website against common vulnerabilities and attacks such as XSS, clickjacking, and data sniffing.

Create Security Headers Configuration File

cd /etc/nginx/includes/
sudo nano http_headers.conf
# Referrer Policy - Controls how much referrer information is shared
add_header Referrer-Policy "strict-origin-when-cross-origin";

# Prevent MIME type sniffing
add_header X-Content-Type-Options "nosniff";

# Prevent clickjacking attacks
add_header X-Frame-Options "sameorigin";

# Enable XSS protection
add_header X-XSS-Protection "1; mode=block";

# Permissions Policy - Control browser features
add_header Permissions-Policy 'accelerometer=(), camera=(), clipboard-read=(), clipboard-write=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), fullscreen=(self "https://www.youtube.com")';

Security Headers Explained

Header Purpose
Referrer-Policy Controls how much referrer information is sent with requests
X-Content-Type-Options Prevents MIME type sniffing attacks
X-Frame-Options Prevents clickjacking by controlling iframe embedding
X-XSS-Protection Enables browser's XSS filtering
Permissions-Policy Controls which browser features can be used

Include Headers in Site Configuration

cd /etc/nginx/sites-available/
sudo nano example.com.conf

Add this line ABOVE your PHP processing location block:

include /etc/nginx/includes/http_headers.conf;
sudo nginx -t
sudo systemctl reload nginx

Browser Caching and Security Headers

sudo nano /etc/nginx/includes/browser_caching_security_headers.conf
expires 30d;
etag on;
if_modified_since exact;
add_header Pragma "public";
add_header Cache-Control "public, no-transform";
try_files $uri $uri/ /index.php?$args;
include /etc/nginx/includes/http_headers.conf;
access_log off;
sudo nginx -t
sudo systemctl reload nginx

WordPress Security Directives

cd /etc/nginx/includes/
sudo nano nginx_security_directives.conf
# WORDPRESS-SAFE NGINX FIREWALL RULESET
# Updated December 2026

# Disable favicon logging
location = /favicon.ico { 
    access_log off; 
    log_not_found off; 
}

# Deny access to sensitive files
location = /wp-config.php { deny all; }
location = /wp-admin/install.php { deny all; }
location ~* ^/(readme|license|licence)\.(txt|html)$ { deny all; }
location ~* \.ini$ { deny all; }

# Harden WP core
location ~* ^/wp-includes/[^/]+\.php$ { deny all; }
location ~* ^/wp-includes/js/tinymce/langs/.+\.php$ { deny all; }
location ~* ^/wp-includes/theme-compat/ { deny all; }

# Prevent PHP execution in sensitive directories
location ~* ^/wp-content/uploads/.*\.(php[1-8]?|pht|phtml?|phps)$ { deny all; }
location ~* ^/wp-content/plugins/.*\.(php[1-8]?|pht|phtml?|phps)$ { deny all; }
location ~* ^/wp-content/themes/.*\.(php[1-8]?|pht|phtml?|phps)$ { deny all; }

# Protect upgrade and backup directories
location ~* ^/wp-content/(upgrade|backup-.*)/.*\.(php[1-8]?|pht|phtml?|phps)$ { deny all; }

# Block development files
location ~* (composer\.(json|lock)|package\.json|yarn\.lock|/vendor/|/node_modules/) { deny all; }

# Block dangerous HTTP methods
if ($request_method ~* ^(TRACE|DELETE|TRACK)$) { 
    return 403; 
}

# Block known vulnerability scanners
if ($http_user_agent ~* (nikto|sqlmap|masscan|nmap|dirbuster|acunetix|openvas)) { 
    return 444; 
}

Include Security Directives in Site Configuration

cd /etc/nginx/sites-available/
sudo nano example.com.conf

Add ABOVE the PHP processing location block:

include /etc/nginx/includes/nginx_security_directives.conf;
sudo nginx -t
sudo systemctl reload nginx

Allowing PHP Execution for Specific Plugins

Some plugins require PHP execution. Here's how to whitelist specific files:

Step 1: Create Test PHP File

cd /var/www/example.com/
sudo nano public_html/wp-content/plugins/test556.php
<?php
phpinfo();
?>

Try accessing: https://example.com/wp-content/plugins/test556.php

You should receive a 403 error (PHP execution blocked).

Step 2: Whitelist Specific Plugin File

sudo nano /etc/nginx/sites-available/example.com.conf

Add this location block AFTER the PHP processing location block:

location = /wp-content/plugins/test556.php { 
    allow all;
    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;
}
sudo nginx -t
sudo systemctl reload nginx && sudo systemctl restart php8.3-fpm

Now the specific plugin file can execute PHP while all others remain blocked.

Step 3: Clean Up Test File

cd /var/www/example.com/public_html/wp-content/plugins/
sudo rm test556.php

๐Ÿ” File Ownership & Permissions

Proper file permissions are crucial for security. Too permissive settings expose your site to attacks, while too restrictive settings break functionality.

Standard Permissions (Development/Regular Use)

cd /var/www/example.com/
sudo chown -R username:username public_html/
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 {} \;
sudo chmod 400 public_html/wp-config.php

Permissions Breakdown

Permission Directories Files Description
Standard 770 660 Owner and group can read/write/execute
Hardened 550 440 Read and execute only (no write)
wp-config.php N/A 400 Read-only by owner

Hardened Permissions (Production/Security)

cd /var/www/example.com/
sudo chown -R username:username public_html/
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 {} \;
โš ๏ธ Understanding Hardened Permissions:

Hardened permissions make most files read-only (440 for files, 550 for directories), which prevents unauthorized modifications. However, WordPress needs write access to certain directories:

  • wp-content/ directory: Plugins, themes, and uploads need write access
  • Uploads remain at 770/660 for functionality
  • Core WordPress files become read-only, preventing tampering

Disable File Modifications in WordPress

Add to wp-config.php to prevent file edits from the dashboard:

define('DISALLOW_FILE_MODS', true);
sudo systemctl reload php8.3-fpm

๐Ÿšฆ Rate Limiting Configuration

Rate limiting prevents brute-force attacks by limiting the number of requests a client can make to sensitive endpoints like wp-login.php and xmlrpc.php.

Step 1: Configure Rate Limiting Zone

cd /etc/nginx/
sudo nano nginx.conf

Add in the http block:

# Rate Limiting
limit_req_zone $binary_remote_addr zone=wp:10m rate=30r/m;
๐Ÿ’ก Rate Limit Explanation:
  • $binary_remote_addr - Track by client IP address
  • zone=wp:10m - Create a 10MB memory zone named "wp"
  • rate=30r/m - Allow 30 requests per minute

Step 2: Create Rate Limiting Include File

cd /etc/nginx/includes/
sudo nano rate_limiting_example.com.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;
}
๐Ÿ’ก Configuration Breakdown:
  • limit_req zone=wp - Use the "wp" rate limiting zone
  • burst=20 - Allow bursts of up to 20 requests
  • nodelay - Process requests immediately without delay
  • limit_req_status 444 - Close connection without response when limit exceeded

Step 3: Include Rate Limiting in Site Configuration

cd /etc/nginx/sites-available/
sudo nano example.com.conf

Add this line:

include /etc/nginx/includes/rate_limiting_example.com.conf;
sudo nginx -t
sudo systemctl reload nginx
โš ๏ธ Important: Remember to update the socket path in your rate limiting configuration file to match your site's PHP-FPM socket (replace example.com with your actual domain).

๐Ÿ’พ Database User Privileges

Limiting database user privileges follows the principle of least privilege, reducing the attack surface if credentials are compromised.

Revoke All Privileges

REVOKE ALL PRIVILEGES ON site_db.* FROM 'site_user'@'hostname';

Grant Minimal Required Privileges

GRANT SELECT, INSERT, UPDATE, DELETE ON site_db.* TO 'site_user'@'hostname';
FLUSH PRIVILEGES;

Grant Additional Privileges (If Needed)

For plugins that create tables or modify database structure:

GRANT CREATE, ALTER, INDEX ON database_name.* TO 'username'@'localhost';
FLUSH PRIVILEGES;

Database Privilege Types

Privilege Purpose Required For
SELECT Read data All WordPress operations
INSERT Add new data Creating posts, comments, users
UPDATE Modify existing data Editing content, settings
DELETE Remove data Deleting posts, comments
CREATE Create tables Plugin installations
ALTER Modify table structure Plugin updates
INDEX Create indexes Performance optimization
๐Ÿ’ก Best Practice:

Start with minimal privileges (SELECT, INSERT, UPDATE, DELETE). Only grant CREATE, ALTER, and INDEX when installing or updating plugins that require them. Remove these elevated privileges after the operation is complete.

๐Ÿ“ Final Configuration Checklist

  • โœ… NGINX logs configured and accessible
  • โœ… PHP-FPM pools created with isolated users
  • โœ… SSL certificates installed and configured
  • โœ… HTTPS redirects working correctly
  • โœ… HTTP/3 and QUIC enabled
  • โœ… Security headers implemented
  • โœ… File permissions hardened
  • โœ… Rate limiting configured
  • โœ… Automated certificate renewal set up
  • โœ… Database privileges restricted
  • โœ… WordPress security rules in place
โš ๏ธ Regular Maintenance Tasks:
  • Check certificate expiry dates regularly: sudo certbot certificates
  • Monitor NGINX error logs: sudo tail -f /var/log/nginx/error.log
  • Review PHP-FPM logs for issues
  • Test SSL rating at ssllabs.com quarterly
  • Update security configurations as new threats emerge
  • Backup your configuration files before making changes