Add a layer of protection between your static HTML frontend and the WordPress API as backend. This will ensure no direct calls can be made against WordPress and gives you control over what kind of requests you allow.

In our previous article “Unleash the WordPress REST API” I showed you how I was able to separate WordPress with a simple HTML frontend.

As I am making AJAX calls directly to my WordPress installation, I still am vulnerable for attacks and my architecture was not able to scale properly. To mitigate this I add a load-balancing reverse proxy and application gateway in the mix using Nginx.

Configure the proxy

Here’s my Nginx configuration nginx.conf to offload the WordPress service from the static HTML frontend.

events {
}

http {
  upstream api {
    server wordpress:80;
  }

  client_max_body_size 20m;
  proxy_cache_path /etc/nginx/cache keys_zone=wp:500m max_size=1000m;

  server {
    proxy_cache wp;
    proxy_cache_key $request_method$request_uri;
    proxy_cache_min_uses 1;
    proxy_cache_methods GET;
    proxy_cache_valid 200 1y;

    location /api {
      if ($request_method != GET) {
        return 405;
      }
      proxy_pass http://api;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      rewrite ^/api(.*)$ /wp-json$1 break;
    }

  }
}

I create an endpoint /api that will be the gatekeeper for connecting with WordPress. If the request is not a GET request, it will be rejected. And only requests for /api will be rewritten to /wp-json on the WordPress backend REST API. All else is ignored.

Add the service for Docker

So in my docker-compose.yml I have added a new nginx service and separate the networks for the WordPress backend with the database and the proxy with the WordPress instance.

version: '3.3'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
     networks:
       - db-net

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
       WORDPRESS_DB_NAME: wordpress
     networks:
       - db-net
       - wp-net

   nginx:
     depends_on:
       - wordpress
     image: nginx:latest
     volumes:
       - ./conf/nginx.conf:/etc/nginx/nginx.conf
     ports:
       - 8001:80
     restart: always
     networks:
       - wp-net

volumes:
  db_data: {}

networks:
  wp-net:
  db-net:

Modify the URI in the static HTML page

In the static HTML file we created earlier, I need to change var backendUri = "http://localhost:8000/wp-json"; into var backendUri = "http://localhost:8001/api"; to access the WordPress instance through the proxy.

Calling the WordPress backend through the Nginx proxy

In my next article I will start serving the HTML page from an Nginx container because now I’m just loading the file straight from my filesystem running a local webserver.


Michelangelo van Dam

Michelangelo van Dam is a senior PHP architect, PHP community leader and international conference speaker with many contributions to PHP projects and community events.