woocommerce logo

WooCommerce Makes a Mess

Saying Goodbye to WooCommerce

Regretfully, I have to admit that WooCommerce makes a mess of the WordPress database. And, since promoting partner products is not the goal of this website. I am separating it from this installation of WordPress.

Do not misunderstand me. WooCommerce is a great and solid product. I enjoy working with it, as much as anything. But, since I need this website to drive leads more than partner sales. I’m giving my partners their own store, off-site.

Sorry for the mess, recently. This will make things much more manageable for me and hopefully easier for you. Now, I only hope Google doesn’t ding me too hard for temporarily 301 redirecting all 404s to my front page (where this is sticky). It’s a price I will just have to pay for a month.

woocommerce is back already
WooCommerce is back already?!

Saying Hello Again to WooCommerce

You can find all of your Acer, TigerDirect and Tech4Less discounts at https://shop.grayhatfreelancing.com.

That being said, let me make a few things clear about the store. The store is just promotional links to my partner’s products. I do not have access to your orders or payment information. The purpose is to allow my clients, potential clients and readers a chance to browse the offers my partners are wanting me to promote. A lot of them are very good deals for very solid products.

Let me be very clear. The shop is NOT a drop ship. Clicking on the product will take you to a product page with a brief description and provide other useful information like prices. Clicking on any of the buy buttons will take you directly to their official store and automatically apply my partner code for you.

I do benefit from the transaction. But, this is one of the few cases where it comes out of their end, not yours.


publish thousands of products

Post Thousands of Products on WooCommerce Instantly

How to Post Thousands of Products on WordPress Instantly

Importing large amounts of product data into WordPress / WooCommerce can be a daunting task. Here’s how you can instantly publish thousands products on WooCommerce using the terminal.

mysql -u dbuser -p dbname
update wp_posts set `post_status` = 'publish' where `post_type` = 'product';
publish thousands of products instantly
If you guessed that we’d use the command line. to publish thousands of products, good for you. 🙂

SQL databases are awesome! That’s right, and you can simply change ‘publish’ to ‘draft’ to delist thousands of products as well. You should take a look through wp_postmeta and see all the various meta keys you can use to filter products and work with your catalog through the command line. It’ll save you time and money.

building a bad ass nginx reverse proxy for wordpress

Building an Awesome NGINX Reverse Proxy for WordPress and Apache

building a bad ass nginx reverse proxy for wordpress
nginx makes a bad ass reverse proxy for wordpress

How to Setup NGINX as a Reverse Proxy for WordPress and Apache

I don’t know why I keep torturing myself, but I do. And you get to enjoy the fruits of my labor. Today, we’re going to setup an Nginx reverse proxy for WordPress, running on Apache. Hopefully, you’re already familiar with configuring Apache for WordPress. It’s pretty straight forward. And, once you get used to the syntax, configuring Nginx is pretty straight forward too.

Apache can be tweaked to be pretty damn fast. Nginx is just plain fast. But, Apache is extremely featureful. So, that’s why I’ve decided to set this up this way. Apache will still have access to it’s robust catalog of modules, but Nginx will handle mosts of the requests coming to the web server.

In case you didn’t catch on, I am going to run these services on the same machine. But, yes, you can host them on different machines.

install nginx reverse proxy for wordpress on apache web server

Installing NGINX Reverse Proxy

I really wish I was able to skip this step, but I can’t. Because, if you already have Apache installed and configured (at least, on Debian, my distribution of choice for this project – fuck systemd), you’ll need to stop apache to install nginx using the apt toolchain*.

You could do several other things, like ensure Apache is not listening on port 80, yadda yadda yadda. This one belongs to the package maintainers for Nginx, if you’re wondering (which, since they maintain their own repo, is likely some systemd loving folks.. I’m sure they’re good people either way, much love for everything Open Source).

systemctl stop apache2
apt install nginx-extras
systemctl stop nginx && systemctl start apache2

Configure NGINX Reverse Proxy for WordPress on Apache Web Server

Now we can get into the meat. First we need to tell the Apache web server to listen on a different port and local only. Port 8080 is popular for standard HTTP, which we’ll use. But, I urge you, especially if your Apache web server is on a different host, to use HTTPS and 8443 (or any non-standard port). You can lock it down, so it only allows the proxy to connect directly, if you like. I won’t cover that here.

Let’s edit /etc/apache2/ports.conf as well as the vhost config for our target domain to be proxied. The vhost config is typically located in /etc/apache2/sites-enabled/vhost.conf
Also ports.conf may simply have that some configuration information in /etc/apache2/apache2.conf (or httpd.conf, the folder can be different, the list goes on).

Change the ports to 8080 and 8443 (or your desired non-standard ports). It’s also safe to turn off HTTP, at this point, if you’re using SSL. This webserver isn’t outward facing, ideally. So, you no longer need the redirect (your plugins may complain).

nginx reverse proxy for wordpress /etc/apache2/ports.conf
nginx reverse proxy for wordpress - netstat antlp

netstat new ports reverse proxy wordpress
desired results at this point

Finalizing NGINX configuration for role as a reverse proxy for WordPress on Apache

From here, you can edit /etc/nginx/sites-available/default if you want. Or you can unlink it from /etc/nginx/sites-enabled/default and start your own new configuration file. I chose the latter option. My Nginx reverse proxy for wordpress isn’t going to use much of the default configuration. So, I just preserved it for later. Lets get some proxy basics set up, outside of the server block and a quick redirect. Open a file in /etc/nginx/sites-available/ (can be editing default or a new file) and add the follow before the server block.

proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
proxy_cache_path /var/run/proxy_cache levels=1:2 keys_zone=REVERSE-PROXY:30m max_size=1000m inactive=60m use_temp_path=off;
proxy_cache_key $scheme$host$request_uri;
proxy_buffers 1024 64k;
proxy_buffer_size 128k;
proxy_set_header Proxy "";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Now we’ll turn port 80 into a 301 redirect to port 443 for SSL. This is the appropriate method for forcing SSL on Nginx by the way, you should not have a server block with both 80 and 443 open.

server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$host$request_uri;
nginx cache proxy server block serving apache

New we get to set some rules specifically for WordPress to work:

# wordpress cookies no-cache
if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
set $skip_cache 1;
set $skip_reason Cookie;
# more wordpress love
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|sitemap(_index)?.xml") {
set $skip_cache 1;
set $skip_reason URI;

Finally, the section where we pipe things over to Apache. This should let you know, we’re almost finsihed.

The Actual NGINX Reverse Proxy for WordPress Configuration

the actual proxy - NOTE: you may need to toggle proxy_redirect on or off if you get a redirect loop when logging into admin
location / {
proxy_set_header Host $host;
proxy_redirect off;
proxy_cache REVERSE-PROXY;
proxy_cache_revalidate on;
proxy_ignore_headers Expires Cache-Control;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_404;
proxy_cache_bypass $skip_cache;
proxy_no_cache $skip_cache;
proxy_cache_valid 200 301 302 360m;
proxy_cache_valid 404 5m;
# feel free to rename PURGE, if you want (here and elsewhere)
proxy_cache_purge PURGE from;
proxy_ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
proxy_ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
nginx reverse proxy location block for proxy config and tls certificate

Now start up nginx with service nginx restart and you’re off to the caches, I mean races. Congratulations!

nginx reverse proxy for wordpress
wordpress deploy from termux

WordPress Deploy from Termux, Hilarious

WordPress Deploy from Termux

Here I am, using performing a wordpress deploy from termux. Using only my cell phone, I launch termux and SSH into my laptop. I create a linux debian virtual machine. Then I connect to that machine, update linux debian 9 aka “buster” to current, linux debian 10 aka “sid”.

wordpress deploy from termux
WordPress Deploy from Termux & Debian Buster Updated to Sid

LAMP Installation and Configuration from Termux

From there, I turn it into a LAMP server. This means I install Apache, MariaDB (a stand-in for MySQL) and PHP. I configure Apache for php-fpm and mpm_event (in a rough way), the I install all the PHP modules required to run WordPress.

MySQL Administration from Android Linux

I also lockdown MariaDB with mysql_secure_installation. I use mysql from command line to create a SQL database and a password protect SQL database user, give the SQL database user access to the SQL database.

I proceed to downloading wordpress and extract it to web root. I set the write file ownership and file permissions for the Apache web server. Finally, I open a browser and configure wordpress’s install script and run it. Followed by creating an administrative user. Completing the first half of my adventure doing a wordpress deploy from termux

wordpress deploy from termux
wordpress deploy from termux

WordPress Installation from a Mobile Phone

I forgot my wordpress administrative password. So, I backup the files and database. Power down the virtual machine. Destroy it. And then I build a new one. But, this time I upgrade linux debian 9 “buster” to linux debian 10 “sid”, or the “bleeding edge”. It’s also known as the unstable branch. I, again, turn it into a LAMP server. And, finally I restore wordpress, from the backup that I made, in the exact same way that you’d recover wordpress from a disaster. Like, if you were hacked or suffered a similar disruption.

WordPress Disaster Recovery

Essential WordPress disaster recovery. And I do it all from my smart phone, using Termux on Android.

Network and Systems Engineering from a Linux Android device
Freelance Gray Hat Hacker for Hire
One of the Best Ways to Migrate WordPress

One of the Best Ways to Migrate WordPress

I’m going to show you how easy it is to migrate WordPress using only the command line. It is just as simple as installing it, in the first place. If you followed the tutorial on deploying wordpress from terminal successfully, you’ll have no trouble with this one.

Migrate WordPress from the Terminal

To be honest, unless you’re using the kick ass wp-cli tool. I’ve found that it’s easiest, and fastest, to use the command line to migrate WordPress. There’s no fiddling about with random plugins that’ll clutter up your database and bother you otherwise. And, in the end, it’s really only a few commands.

All we need to do is make sure we have all of the files and the file structure intact, as well as the database. If you’re moving from one domain name to another, you may need to find and replace in the database, everywhere your origin domain exists with your destination domain. Or, you could just update the website’s settings with your destination domain prior to performing the migration.

We’ll touch on fixing the configuration, if you forgot to update your domain before the migration, at the end.

Zip and Grab the WordPress Files

Go ahead and SSH into the machine hosting WordPress that you plan to migrate and zip up the entirety of the wordpress directory.

ssh <source host>
cd /var/www/html
sudo zip -r wordpress-migration.zip *
sudo mv wordpress-migration ~
compress files into a zip archive for a wordpress migration
zip -r target-zip-file.zip $path

You’ll see a lot of spam fly by as zip recursively compresses all of the files in preparation for our WordPress migration. Finally, I move the zip archive back to my user directory, where all that’s left for that part is to change the ownership to my user and pull it down. But, we still need the database or we won’t have anything for users or content or anything that matters.

Saving the WordPress Database for Migration

sudo mysql_dump -u wp_db_user -p wp_database > wordpress-database-backup.sql
chown mootiny:mootiny wordpress-database-backup.sql
chown mootiny:mootiny wordpress-backup.zip
extracting a SQL database for a WordPress migration
mysqldump backs dat ass up

Migrating the WordPress Website to the New Host

Now migrate your files to your new host. In case you haven’t noticed, this is exactly how you’d perform disaster recovery on a WordPress website that’d been compromised or suffered a hardware failure or anything else catastrophic. As well, it’s not far from manually deploying WordPress from the terminal either.

migrating wordpress files to a new host using sftp
put’n those files where they belong

Go ahead and use SFTP (which comes bundled with OpenSSH) to connect to your new host and transfer your backup for restoration and recovery.

sftp <destination host>
put wordpress-database-backup.sql
put wordpress-backup.zip

Now we simply extract the WordPress files on their new host. Then we will fix the file permissions. Create an empty database, database user and restore the SQL database at it’s new home.

creating a mariadb database and user, then granting the user access to the database, while manually performing a wordpress migration using only the terminal
creating the wordpress database and user for a wordpress migration (from terminal)

Change directories to webroot (if that’s where you want WordPress to live). Extract the files and proceed to log into the SQL server.

cd /var/www/html
sudo unzip ~/wordpress-backup.zip

Next we connect to our MariaDB server and create a shell for our WordPress website to move into.

sudo mysql -u root -p
MySQL> create database wp_database;
MySQL> grant all privileges on wp_database.* to 'wp_db_user'@localhost identified by 'wp_db_password';
MySQL> flush privileges;
MySQL> quit;

Now that we have a skeleton in place, all we need to do is restore the SQL content by populating the database with a quick one-liner and fix the file permissions and we’re golden!

mysql -u wp_db_user -p wp_database < wordpress-database-backup.sql

Setting the Correct Permissions after our WordPress Migration

restoring the WordPress database to MariaDB server and fixing the file permissions for a wordpress migration
fixing file permissions
chown -R www-data:www-data /var/www/html
find /var/www/html -type d -exec chown 755 {} \;
find /var/www/html -type f -exec chown 644 {} \;

And you’re done, browse to your new host and login through the web interface, like normal. 🙂

migrating wordpress from the terminal is successful!
terminal only wordpress deploy

A Perfect WordPress Deployment using the Terminal

How to Manually Perform a WordPress Deployment

I’m going to walk you through a WordPress deployment, using only the terminal. This is mostly because I need to put some content up here. And, once upon a time, this used to be one of my staple articles. Nothing has changed, really. But, I will reiterate the fact that you really should know how to do things manually, because you start plowing ahead and automating them.

Automation is good, it’s absolutely necessary, even. But, when things break, it’s best that you’re able to figure it out how it happened. And, the easiest way to obtain that information is, sadly, the hard way.

WordPress being so evolved.. Please do not expect a WordPress deploy to be something you can’t handle. Deploying WordPress is very straightforward. So, let’s get started.

virtual guest linux debian in a vagrant
Linux Debian 9 as a vagrant guest

LAMP: Linux, Apache, MySQL and PHP

WordPress runs very well on almost any web server. But, for the purposes of sticking to the documentation, we’re going to use Apache (not that I always stick to the documentation, mind you). You should familiarize yourself with a “LAMP” deployment anyway, it’s pretty much what powers the entire internet. Please note that MySQL is often replaced with either MariaDB or Percona Server. I won’t go into the differences here.

Go ahead and SSH into your web server, update your software repository and do a full system upgrade. There’s no reason to deploy LAMP without the latest patches. I’m using debian, so your commands may be slightly different for these types of things. Refer to your distributions handbook, if you need to.

sudo apt update
sudo apt dist-upgrade
sudo apt install apache2 mariadb-server php-fpm

Enable the Necessary Apache Modules

Hah! Before, that required us grabbing a whole lot more packages than it does these days. But, don’t worry! We will still need to go get various PHP libraries for our WordPress deploy to be successful (specifically, for it to interact with mariadb). Still, you don’t need to do anything else there on Debian, unless Apache was previously configured with libapache2-mod-php. Then go ahead and issue the following (unexplained):

sudo a2dismod php
sudo a2dismod mpm_prefork
sudo a2enconf php7.3-fpm (at time of writing, 7.3 was stable)
sudo a2enmod mpm_event fcgid cgi proxy_fcgi setenvif rewrite
using terminal to swap apache modules for a manual wordpress deploy
Configure Apache

There’s plenty of other Apache modules that are beneficial for WordPress, but we’re just doing a deploy right now.

Prepare MariaDB for Production

I’m pretty sure that we all knew MySQL shipped with insecure defaults for many years. So, I have no idea, why this tradition has carried through to MariaDB. But, it’s my opinion, that we should damn not be having to still do this bit here. But, set a root password for the SQL db. And, disable remote access. Run ‘mysql_secure_installation’, press Y to everything and set a password.

Install the Minimum PHP Requirements

As I just said about Apache, there’s also plenty of PHP libraries that will benefit WordPress, but they’re beyond the scope of this walk through. So, we’re only going to grab what WordPress requires to install without complaint, as well as what is required to return a green health check.

sudo apt install php-mysql php-gd php-bz2 php-curl php-zip php-xml php-gmp php-intl php-mbstring php-xmlrpc php-token-stream php-mcrypt
manual wordpress deploy, installing required php modules
install php modules

I, honestly, don’t know what to tell you about PHP modules. Depending on your linux distribution, your PHP package is going to come with different modules. There’s really no telling what was bundled with it and what wasn’t. If you’re on Debian, this will get WordPress up and running, at least. But, on others, the packages will be named differently anyway. So, try to reach this minimum.

WordPress Deployed from Terminal

On Debian, Apache’s default “webroot” is in /var/www/html . Your “webroot” may be in a different location. If you don’t know, check your Apache configuration. It should be located in /etc/apache2 or /etc/httpd – The filename would either be apache2.conf or httpd.conf

Anyway, back to manually WordPress deploying from the terminal. I’ll have to clean this up later. But, for now, I’ll just finish what I started. Jump on over to webroot, grab the latest version from wordpress.org and extract it. All that’s left after that is to create a user for “MySQL”, set permissions and run the installer.

cd /var/www/html
wget https://wordpress.org/latest.zip
unzip latest.zip
quite literally deploying wordpress into a folder, out of compressed zip file
extract wordpress

Note: this next part you can ignore. What I am doing is deleting my webroot and moving the folder wordpress extracted to in place of my webroot. If you extracted wordpress into ./html/ then you don’t need to do this.

rm -rf ./html/
mv ./wordpress/ ./html/

Create a MySQL Database, a MySQL User, Marry Them

Now we need to create a MySQL database. Create a MySQL user and grant it privileges to write to the database. Then, fix the file permissions and we’re done with the terminal (the website is technically up, a that point.

mysql -u root -p (perhaps prefix with sudo, if you're not root)
mysql> create database wordpress;
mysql> grant all privileges on wordpress.* to 'wordpress'@localhost identified by '[email protected]';
mysql> flush privileges;
mysql> quit
grant all privileges on WordPress Deploy to Deploy@WordPress identified by 'ASSWORD'
Identified by assword?!

Let’s set some privileges, first give the user that runs Apache ownership of the files. Then set the directories to read/write, read/write by Apache’s user and group. Finally, give the files read/write to Apache’s user and read/execute to everyone else (since php-fpm needs to read and run them).

Fix File Permissions and Be Done!

chown -R www-data:www-data /var/www/html
find /var/www/html -type d -exec chmod 755 {} ;
find /var/www/html -type f -exec chmod 644 {} ;

At this point, we really need to bust out our browser and complete the install, so we can prevent about a billion zombies from hammering away at our install script and owning the box (just log password attempts on WordPress for a week and you’ll see what I mean). So get your browser out and finish this bitch off! You’re done.

Good luck. Have fun! And, next map. If you’d like this handled for you, drop me a line at Gray Hat Freelancing!

wordpress initial configuration - final step of wordpress deployment
Porky Pig

FIN – Our Job Here is Done

There’s plenty more to do. Especially from a security standpoint. I can tell you right now, our file permissions are decent but not perfect. There’s optimizations that need to be made or your blog could become a zombie in a DDoS, etc.. But, those are for another article. For now, enjoy the WordPress deploy!

wordpress has been deployed - hello world
Hello World!
deploying wordpress - do the speak english in wordpress deployment?
wordpress database configuration - almost done with wordpress deployment