Bulletproof WordPress via Nginx

I assume many developers consider WordPress as a joke since it’s made with “PHP”. However, WordPress is still powering a lot of websites. So quite often it is inevitable to do some work on a project that deals with WordPress.

Personally, I’ve had to deal with many WordPress sites and resolve security issues. The most common issues that I observed have been:

  • Backdoor attack to use the infected host to perform various types of attack
  • Stealing an admin cookie
  • Using the stolen cookie to post many dangerous posts
  • Using the stolen cookie to upload other scripts in wp-content directory
  • And so on

The most used attack paths the hackers/hacking tools seem to be wp-admin/(post-new|post|admin-post|).php and /wp-login.php.

Anyhow, the most impactful defense mechanism that I found was to whitelist IP address that belongs to a certain admin user. So far, nothing else has beaten that solution, so I call it a bulletproof Nginx config for WordPress site.

Here’s my Nginx config that I used for my clients to prevent hackers from attempting to intrude a WordPress site.

  location ~ /wp-admin/admin-ajax\.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_read_timeout 300;
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    allow all;
  }

  location ~ (/wp-admin/.*\.php|wp-login\.php$) {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_read_timeout 300;
    fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;

    ## whitelist IPs
    allow x.x.x.x;
    deny all;
    error_page 403 = @wp_ban;
  }

  location @wp_ban {
    rewrite ^(.*) https://mysite.com permanent;
  }

  location ~* /(?:uploads|files|wp-content|wp-includes|akismet)/.*.php$ {
    deny all;
    access_log off;
    log_not_found off;
  }

Smooth move to a new host

Before I started moving this site to a new host (slicehost.com), my plan was very simple in my head. My plan that I followed was:

  1. Export Data using word press admin’s tool
  2. Create database called ‘wpblog’ in a new host
  3. Create database user and password
  4. Download wp and copied them to a new host (it will be a brand new wp)
  5. Update wp-config.php to reflect the newly created database name, user, and password
  6. Updated *hosts* file to map my domain to the new host’s IP address
  7. Fired up a browser, went to the domain (where wp is newly installed)
  8. Followed the instruction to install wp
  9. Go to admin using “admin” account and the password wordpress auto generated
  10. Change wp-content directory’s permission to 777 by using FTP client or SSH and chmod it.
  11. Use *Import* from Tools in the admin page
  12. Choose auto import photos or images.. something like that
  13. Copy theme in the old host to a new host
  14. Copy all plugins in the old host to a new host
  15. Download *search and replace* from this link and install it
  16. Select the theme that’s just copied over from the old host
  17. Activate plugins that are just copied over from the old host
  18. Look for broken images or any attachments in pages.
  19. (If found, write down the host name(usually IP address) that is in img src or somewhere like that. Go to admin page, activate *search and replace* plugin, go to *search and replace* page found in the settings, select *content*, type the host name found in the previous step, type the current host name, and then hit *Go*
  20. Switch name server after verifying everything is intact.

I think the steps that I mentioned above should let you move your wordpress to a new host very smoothly. However, you might wonder what you really have to do in each step specifically the followings:

Continue reading

in Tips | 533 Words