Deploy Node.js App: PM2 and Nginx Guide
Complete guide to deploying Node.js applications on a VPS. Node.js installation with nvm, PM2 process manager, Nginx reverse proxy, SSL certificate, and environment variables management.
Optimal server configuration for WordPress: LEMP stack, PHP-FPM, Nginx FastCGI cache, Redis, MariaDB tuning, OPcache and CDN setup. Recommended specs for different traffic levels.
WordPress is the world's most popular content management system. However, performance issues can occur when running with default configurations. This guide explains step by step the optimal server configuration to run your WordPress site quickly and reliably.
| Traffic Level | Monthly Visitors | CPU | RAM | Storage | Recommended Plan |
|---|---|---|---|---|---|
| Small | < 10,000 | 2 vCPU | 2 GB | 20 GB NVMe | VPS Starter |
| Medium | 10,000 - 100,000 | 4 vCPU | 4-8 GB | 50 GB NVMe | VDS Starter |
| Large | 100,000 - 500,000 | 8 vCPU | 16 GB | 100 GB NVMe | VDS Pro |
| Enterprise | 500,000+ | 16+ vCPU | 32+ GB | 200+ GB NVMe | Dedicated |
The LEMP stack (Linux + Nginx + MariaDB + PHP-FPM) provides the best performance for WordPress. It uses less memory than Apache and supports higher concurrent connections.
# Update system
sudo apt update && sudo apt upgrade -y
# Install Nginx
sudo apt install nginx -y
# Install MariaDB
sudo apt install mariadb-server mariadb-client -y
# Install PHP and required extensions
sudo apt install php8.2-fpm php8.2-mysql php8.2-xml php8.2-gd \
php8.2-curl php8.2-mbstring php8.2-zip php8.2-intl \
php8.2-bcmath php8.2-imagick php8.2-redis -y
Optimizing PHP-FPM for WordPress improves memory usage and response times.
sudo nano /etc/php/8.2/fpm/pool.d/wordpress.conf
[wordpress]
user = www-data
group = www-data
listen = /run/php/php8.2-fpm-wordpress.sock
; Dynamic process management
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
; PHP settings
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M
php_admin_value[max_execution_time] = 300
php_admin_value[max_input_vars] = 3000
Nginx FastCGI cache bypasses PHP processing and responds as fast as static content.
# Define FastCGI cache zone
fastcgi_cache_path /var/cache/nginx/wordpress
levels=1:2
keys_zone=WORDPRESS:100m
inactive=60m
max_size=1g;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
server {
listen 443 ssl http2;
server_name example.com www.example.com;
root /var/www/wordpress;
set $skip_cache 0;
# Don't cache POST requests and query strings
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
# Don't cache WordPress admin and special URLs
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/") {
set $skip_cache 1;
}
# Don't cache logged-in users
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wordpress_logged_in") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm-wordpress.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 60m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-FastCGI-Cache $upstream_cache_status;
}
# Long cache for static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location ~ /\.ht { deny all; }
location = /xmlrpc.php { deny all; }
}
Redis caches WordPress database queries, significantly reducing page load times.
# Install Redis
sudo apt install redis-server -y
# Redis configuration
maxmemory 256mb
maxmemory-policy allkeys-lru
save ""
unixsocket /var/run/redis/redis-server.sock
unixsocketperm 770
// Add to wp-config.php
define('WP_REDIS_HOST', '/var/run/redis/redis-server.sock');
define('WP_REDIS_PORT', 0);
define('WP_REDIS_DATABASE', 0);
Install and activate the "Redis Object Cache" plugin from the WordPress admin panel.
[mysqld]
# InnoDB settings
innodb_buffer_pool_size = 1G # 50-70% of RAM
innodb_buffer_pool_instances = 4
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
# Query cache
query_cache_type = 1
query_cache_size = 64M
query_cache_limit = 2M
# Connection settings
max_connections = 150
wait_timeout = 60
# Temporary tables
tmp_table_size = 64M
max_heap_table_size = 64M
# Slow query log
slow_query_log = 1
long_query_time = 2
OPcache caches PHP code as compiled bytecode, eliminating the need to recompile on every request.
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
opcache.jit=1255
opcache.jit_buffer_size=128M
A CDN (Content Delivery Network) distributes your static files to servers worldwide, reducing load times.
// Add to wp-config.php (behind Cloudflare)
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
// wp-config.php security settings
define('DISALLOW_FILE_EDIT', true); // Disable theme/plugin editor
define('FORCE_SSL_ADMIN', true); // Force HTTPS for admin
define('WP_DEBUG', false); // Debug off (production)
define('AUTOMATIC_UPDATER_DISABLED', false); // Auto updates on
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup/wordpress"
mkdir -p $BACKUP_DIR
# Backup database
mysqldump -u wpuser -pwppassword wordpress | \
gzip > $BACKUP_DIR/db_$DATE.sql.gz
# Backup files
tar -czf $BACKUP_DIR/files_$DATE.tar.gz \
--exclude=/var/www/wordpress/wp-content/cache \
/var/www/wordpress
# Delete backups older than 30 days
find $BACKUP_DIR -mtime +30 -delete
To improve WordPress performance, apply the optimizations with the biggest impact first: 1) OPcache, 2) FastCGI cache, 3) Redis object cache, 4) CDN. These four steps speed up most WordPress sites by 5-10x.
Nginx is generally a better choice for WordPress. It uses less memory than Apache, supports higher concurrent connections, and provides much faster response times with FastCGI cache. The advantage of Nginx becomes especially pronounced on high-traffic sites.
Redis is recommended for WordPress. Redis offers richer data structures than Memcached, has a persistence option, and provides excellent integration with the WordPress Redis Object Cache plugin. Redis also works better with e-commerce plugins like WooCommerce.
FastCGI cache works at the Nginx level and responds by completely bypassing PHP. This is much faster than WordPress plugin-based cache solutions. W3 Total Cache and WP Super Cache work within PHP. If you're using server-level FastCGI cache, you generally don't need an additional WordPress cache plugin.
You can start with a minimum of 2 GB RAM, but 4 GB is recommended. High-traffic sites may need 8-16 GB. RAM calculation: ~50-100 MB per PHP-FPM process, ~1 GB for MariaDB, ~256 MB for Redis, ~50 MB for Nginx. Calculate total needs accordingly.
Yes, some additional settings are required for WooCommerce. Cart and checkout pages should not be cached (add FastCGI cache bypass rules). Use Redis session storage. Set PHP memory_limit to at least 256 MB. Consider ProxySQL or PgBouncer for database connection pooling. VDS or Dedicated server is recommended for high-traffic WooCommerce sites.
Complete guide to deploying Node.js applications on a VPS. Node.js installation with nvm, PM2 process manager, Nginx reverse proxy, SSL certificate, and environment variables management.
Complete guide to deploying PHP applications on a VPS. LAMP vs LEMP comparison, Apache/Nginx + PHP-FPM + MySQL setup, virtual host configuration, and PHP version management.
Guide to installing and optimizing WordPress on a VPS. LEMP stack setup, wp-config.php settings, file permissions, SSL, OPcache performance optimization, and security hardening.