Dev Portfolio
Back to Writings

Cloud Notes: WordPress on EFS with CloudFront + ALB + Nginx

Production-ready, step-by-step guide to running WordPress on EFS behind CloudFront and ALB using Nginx.

Jan 2, 2025

WordPress on EFS + CloudFront + ALB (Production Guide)

Case

You are running Ubuntu + Nginx on EC2. Traffic flows through CloudFront → ALB → EC2. TLS terminates at CloudFront (or ALB). WordPress files live on EFS (NFS) mounted at:

/var/www/portal/wordpress

Database is Amazon RDS in the same VPC.

Your goals:

  • Correct WordPress install on EFS
  • No mixed-content issues
  • Proper handling of X-Forwarded-* headers
  • Clean, production-ready Nginx config

Assumptions (important)

  • HTTPS terminates at CloudFront or ALB
  • EC2 only receives HTTP (port 80)
  • CloudFront → ALB → EC2
  • EFS already mounted at /var/www

STEP 1: Install required packages

sudo apt update
sudo apt upgrade -y
sudo apt install -y nginx nfs-common \
  php8.3 php8.3-fpm php8.3-mysql php8.3-xml php8.3-mbstring \
  php8.3-curl php8.3-zip php8.3-bcmath php8.3-gd

Verify PHP:

php -v

Assumed PHP-FPM socket:

/run/php/php8.3-fpm.sock

STEP 2: Prepare directory structure (EFS)

sudo mkdir -p /var/www/portal/wordpress
sudo chown -R www-data:www-data /var/www/portal
sudo chmod -R 755 /var/www/portal

Important for EFS write access:

sudo chmod -R 775 /var/www/portal/wordpress

STEP 3: Download WordPress

cd /tmp
curl -O https://wordpress.org/latest.tar.gz
tar xzf latest.tar.gz
sudo rsync -av wordpress/ /var/www/portal/wordpress/

Fix ownership:

sudo chown -R www-data:www-data /var/www/portal/wordpress

STEP 4: Configure WordPress (wp-config.php)

cd /var/www/portal/wordpress
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.php

Database (RDS)

define('DB_NAME', 'wordpress_db');
define('DB_USER', 'db_user');
define('DB_PASSWORD', 'db_password');
define('DB_HOST', 'your-rds-endpoint.amazonaws.com');
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

Fix HTTPS & mixed content (VERY IMPORTANT)

Add immediately after <?php:

if (
    isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
    $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'
) {
    $_SERVER['HTTPS'] = 'on';
}

define('WP_HOME', 'https://your-domain.com');
define('WP_SITEURL', 'https://your-domain.com');

Purpose:

  • Prevents mixed content
  • Avoids redirect loops
  • Required for CloudFront + ALB

Security keys

Generate keys:

šŸ‘‰ https://api.wordpress.org/secret-key/1.1/salt/

Replace all auth keys in wp-config.php.


STEP 5: Nginx configuration

Create site config:

sudo nano /etc/nginx/sites-available/portal-wordpress

Nginx (CloudFront / ALB ready)

server {
    listen 80;
    server_name _;

    root /var/www/portal/wordpress;
    index index.php index.html;

    fastcgi_read_timeout 600;
    client_max_body_size 1024M;

    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location = /health {
        access_log off;
        default_type text/plain;
        return 200 "OK";
    }

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_param HTTPS on;
        fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
        fastcgi_param HTTP_X_FORWARDED_SSL on;
    }

    location ~ /\.ht {
        deny all;
    }

    location ~* /wp-config.php {
        deny all;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 30d;
        access_log off;
    }
}

Enable site:

sudo ln -s /etc/nginx/sites-available/portal-wordpress /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default

Reload:

sudo nginx -t
sudo systemctl reload nginx

STEP 6: PHP-FPM tuning

PHP settings

sudo nano /etc/php/8.3/fpm/php.ini

Recommended:

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 300

PHP-FPM process manager tuning (important)

Edit pool configuration:

sudo nano /etc/php/8.3/fpm/pool.d/www.conf

Set / adjust:

pm = dynamic
pm.max_children = 40
pm.start_servers = 10
pm.min_spare_servers = 10
pm.max_spare_servers = 20

Notes:

  • Tune based on EC2 instance size and available RAM
  • Prevents request queue buildup under load
  • Important for WordPress behind CloudFront

Restart PHP-FPM:

sudo systemctl restart php8.3-fpm

STEP 7: Test database connectivity

mysql -h your-rds-endpoint.amazonaws.com -u db_user -p

If it fails:

  • RDS SG allows EC2 SG
  • Same VPC / routing

STEP 8: Finish WordPress installation

Open:

https://your-domain.com

Expected:

  • Clean HTTPS
  • No mixed content
  • Admin dashboard works

STEP 9: Extra hardening

define('FORCE_SSL_ADMIN', true);

STEP 10: CloudFront configuration notes

Architecture

Viewer (HTTPS :443)
→ CloudFront
→ ALB (HTTP :80)
→ EC2 (HTTP :80)

Origin (ALB)

SettingValue
Origin typeCustom origin
Origin domainALB DNS name
Origin protocol policyHTTP only
HTTP port80

CloudFront behaviors (recommended)

PriorityPathCacheNotes
0/wp-admin/*DisabledAdmin must not be cached
1/wp-json/*DisabledREST API / Gutenberg
2/wp-content/*OptimizedStatic assets
3/wp-includes/*OptimizedCore static files
4*DisabledDynamic pages

Headers:

  • X-Forwarded-Proto
  • Host

Viewer policy:

  • Redirect HTTP → HTTPS

Final checklist

  • WordPress runs on EFS (/var/www/portal/wordpress)
  • No mixed content
  • CloudFront + ALB compatible
  • Nginx optimized
  • RDS connected