- DigitalOcean Ubuntu 24.04 LTS server with root or sudo access
- Domain name pointed to your server's IP address
- Cloudflare account with domain added
sudo apt update && sudo apt upgrade -ysudo apt install curl wget unzip software-properties-common -ysudo systemctl stop apache2
sudo systemctl disable apache2
sudo apt purge apache2 apache2-utils apache2-bin apache2-data -y
sudo apt autoremove -y
sudo apt autocleansudo rm -rf /etc/apache2
sudo rm -rf /var/www/htmlsudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginxsudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enablesudo apt install mysql-server -y
sudo systemctl start mysql
sudo systemctl enable mysqlsudo mysql_secure_installationFollow the prompts:
- Set root password: Yes
- Remove anonymous users: Yes
- Disallow root login remotely: Yes
- Remove test database: Yes
- Reload privilege tables: Yes
sudo mysql -u root -pIn MySQL prompt:
CREATE DATABASE wordpress_db;
CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;sudo apt install php php-fpm php-mysql php-curl php-gd php-intl php-mbstring php-soap php-xml php-xmlrpc php-zip php-cli php-common php-opcache -ysudo systemctl start php8.3-fpm
sudo systemctl enable php8.3-fpmsudo vim /etc/php/8.3/fpm/php.iniUpdate these settings:
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 300
max_input_vars = 3000Restart PHP-FPM:
sudo systemctl restart php8.3-fpmcd /tmp
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gzReplace your-domain.com with your actual domain name:
sudo mkdir -p /var/www/your-domain.com
sudo cp -R wordpress/* /var/www/your-domain.com/
sudo chown -R www-data:www-data /var/www/your-domain.com/
sudo chmod -R 755 /var/www/your-domain.com/cd /var/www/your-domain.com/
sudo cp wp-config-sample.php wp-config.php
sudo vim wp-config.phpUpdate database settings:
define('DB_NAME', 'wordpress_db');
define('DB_USER', 'wp_user');
define('DB_PASSWORD', 'your_strong_password');
define('DB_HOST', 'localhost');Add security keys (get from https://api.wordpress.org/secret-key/1.1/salt/):
define('AUTH_KEY', 'your-unique-key');
define('SECURE_AUTH_KEY', 'your-unique-key');
define('LOGGED_IN_KEY', 'your-unique-key');
define('NONCE_KEY', 'your-unique-key');
define('AUTH_SALT', 'your-unique-key');
define('SECURE_AUTH_SALT', 'your-unique-key');
define('LOGGED_IN_SALT', 'your-unique-key');
define('NONCE_SALT', 'your-unique-key');Replace your-domain.com with your actual domain name:
sudo vim /etc/nginx/sites-available/your-domain.comAdd this configuration:
server {
listen 80;
server_name your-domain.com www.your-domain.com;
root /var/www/your-domain.com;
index index.php index.html index.htm;
# 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;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# WordPress security
location ~ /\.ht {
deny all;
}
location = /xmlrpc.php {
deny all;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Block access to sensitive files
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
}sudo ln -s /etc/nginx/sites-available/your-domain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx- Login to Cloudflare dashboard
- Go to your domain → SSL/TLS
- Set SSL/TLS encryption mode to "Full (strict)"
- In Cloudflare dashboard, go to SSL/TLS → Origin Server
- Click "Create Certificate"
- Choose "Let Cloudflare generate a private key and a CSR"
- Select RSA 2048-bit key
- Set hostname to
*.your-domain.com, your-domain.com - Choose certificate validity (15 years recommended)
- Click "Create"
sudo mkdir -p /etc/ssl/cloudflare
sudo vim /etc/ssl/cloudflare/cert.pemPaste the Origin Certificate content.
sudo vim /etc/ssl/cloudflare/key.pemPaste the Private Key content.
sudo chmod 400 /etc/ssl/cloudflare/key.pem
sudo chmod 444 /etc/ssl/cloudflare/cert.pem
sudo chown root:root /etc/ssl/cloudflare/*sudo vim /etc/nginx/sites-available/your-domain.comReplace the content with:
server {
listen 80;
server_name your-domain.com www.your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com www.your-domain.com;
root /var/www/your-domain.com;
index index.php index.html index.htm;
# SSL Configuration
ssl_certificate /etc/ssl/cloudflare/cert.pem;
ssl_certificate_key /etc/ssl/cloudflare/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 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;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Add real IP from Cloudflare
fastcgi_param HTTP_CF_CONNECTING_IP $http_cf_connecting_ip;
}
# WordPress security
location ~ /\.ht {
deny all;
}
location = /xmlrpc.php {
deny all;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Block access to sensitive files
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
}sudo nginx -t
sudo systemctl reload nginxAdd these lines to your wp-config.php file:
sudo vim /var/www/your-domain.com/wp-config.phpAdd before "/* That's all, stop editing! */":
// Cloudflare support
if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
}
// Force SSL
define('FORCE_SSL_ADMIN', true);
if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
$_SERVER['HTTPS'] = 'on';
}
// WordPress URLs
define('WP_HOME','https://your-domain.com');
define('WP_SITEURL','https://your-domain.com');- Visit
https://your-domain.comin your browser - Follow the WordPress installation wizard
- Create admin account and complete setup
Install Wordfence Security or Sucuri Security plugin for additional protection through the WordPress admin dashboard:
- Visit
https://your-domain.com/wp-admin - Go to Plugins → Add New
- Search for "Wordfence Security"
- Install and activate the plugin
- Configure security settings as needed
- Yoast SEO: Search engine optimization
- W3 Total Cache: Performance optimization
- UpdraftPlus: Backup solution
- Two Factor: Two-factor authentication
In your Cloudflare dashboard:
-
Speed → Optimization:
- Enable Auto Minify (CSS, JavaScript, HTML)
- Enable Brotli compression
-
Caching → Configuration:
- Set Browser Cache TTL to "1 month"
- Enable "Always Online"
-
Security → Settings:
- Set Security Level to "Medium"
- Enable "Challenge Passage"
sudo apt install redis-server -y
sudo systemctl start redis
sudo systemctl enable redissudo apt install php-redis -y
sudo systemctl restart php8.3-fpm- Visit
https://your-domain.com/wp-admin - Go to Dashboard → Updates
- Update WordPress core and plugins as needed
sudo mysqldump -u root -p wordpress_db > wordpress_backup_$(date +%Y%m%d).sqlsudo find /var/www/your-domain.com/ -type d -exec chmod 755 {} \;
sudo find /var/www/your-domain.com/ -type f -exec chmod 644 {} \;
sudo chown -R www-data:www-data /var/www/your-domain.com/sudo systemctl status nginx
sudo systemctl status mysql
sudo systemctl status php8.3-fpmsudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/php8.3-fpm.logopenssl s_client -connect your-domain.com:443 -servername your-domain.com- Check if PHP-FPM is running:
sudo systemctl status php8.3-fpm - Verify socket path in Nginx config matches PHP-FPM socket
- Check Nginx error logs:
sudo tail -f /var/log/nginx/error.log
- Verify database credentials in
wp-config.php - Test database connection:
mysql -u wp_user -p wordpress_db - Check MySQL service:
sudo systemctl status mysql
- ✅ Strong database passwords
- ✅ WordPress security keys configured
- ✅ File permissions set correctly
- ✅ SSL/TLS encryption enabled
- ✅ Security headers configured
- ✅ Xmlrpc.php blocked
- ✅ Directory browsing disabled
- ✅ PHP file execution in uploads blocked
- Replace placeholders: Change
your-domain.com,your_strong_password, etc. with your actual values - DNS settings: Make sure your domain's DNS is pointing to Cloudflare's nameservers
- Cloudflare settings: The "Full (strict)" SSL mode ensures end-to-end encryption
- Backup strategy: Set up automated backups for both files and database
Your WordPress site should now be running securely with Nginx and Cloudflare SSL protection!
Found an issue or want to improve this guide? Feel free to open an issue or submit a pull request.
This guide is provided as-is under the MIT License. Use at your own risk.