One thing to try when Wordfence breaks your server

I opened up my local copy of one of our sites today and… white screen. WTF, it was working fine the last time I used it. I hit reload and now I’m getting a server not found error. That’s weird.

So I check the log files and see this:

[Mon May 07 15:09:14 2018] [notice] Child 167276: Starting thread to listen on port 80.
[Mon May 07 15:09:16 2018] [notice] Parent: child process exited with status 255 — Restarting.
[Mon May 07 15:09:17 2018] [notice] Digest: generating secret for digest authentication …
[Mon May 07 15:09:17 2018] [notice] Digest: done
[Mon May 07 15:09:19 2018] [notice] Apache/2.2.31 (Win32) DAV/2 mod_ssl/2.2.31 OpenSSL/1.0.2e mod_fcgid/2.3.9 mod_wsgi/3.4 Python/2.7.6 PHP/7.1.7 mod_perl/2.0.8 Perl/v5.16.3 configured — resuming normal operations
[Mon May 07 15:09:19 2018] [notice] Server built: May 6 2016 10:19:53
[Mon May 07 15:09:19 2018] [notice] Parent: Created child process 50416
[Mon May 07 15:09:20 2018] [notice] Digest: generating secret for digest authentication …
[Mon May 07 15:09:20 2018] [notice] Digest: done
[Mon May 07 15:09:21 2018] [notice] Child 50416: Child process is running
[Mon May 07 15:09:21 2018] [notice] Child 50416: Acquired the start mutex.
[Mon May 07 15:09:21 2018] [notice] Child 50416: Starting 64 worker threads.
[Mon May 07 15:09:21 2018] [notice] Child 50416: Starting thread to listen on port 80.
[Mon May 07 15:09:23 2018] [notice] Parent: child process exited with status 255 — Restarting.

This repeated over and over. Apache was starting but when I attempted to load the site, it would crash. If I tried to load something simple that didn’t involve wordpress, everything worked fine.

Long story short, something had become foobar’d with Wordfence. Not blaming the plugin itself, I think I munged something up when I imported a fresh SQL dump. I usually don’t pull over wordfence directories but maybe I screwed up, who knows?

The fix is simple enough.

Step 1:
Delete everything in \public_html\wp-content\wflogs

Step 2:
Truncate all the wp_wf* tables in your database.

Bam, problem hopefully solved. Wordfence will recreate the files you delete and re-fill that tables as it needs to. And your local will start to work again. Huzzah!

Now if it happens again, you might have a bigger issue. What turned out to be the problem in my case was that Wordfence was exhausting Apache’s memory, essentially. This only happened for me in a MAMP environment; I never ran into the issue with my Docker-based locals.

I fixed it by tweaking the Apache ThreadStackSize by inserting this into http.conf:

ThreadStackSize 8388608

Since I was on MAMP I had to edit a template. See this post for more on dealing with MAMP templates.

Apparently (I read this on the Internet so it must be true) MAMP sets a much smaller default stack size (1 MB) as compared to a typical Linux installation (8 MB). So the above ThreadStackSize pushes the size to the same as you’d find on linux.

Creating a self-signed SSL certificate for local Docker development

Usually I don’t bother setting up SSL for local development but sometimes you’ll be using a service that requires it. Plus, more and more browsers are pushing you towards SSL all the time. [Side note, I wish someone would make a browser just for developers that gets out of the way and stops trying to protect us from ourselves when we’re working on local sites.]

A lot of folks are moving towards using Let’s Encrypt for free SSL certs but I’m either stubborn or dumb. Basically I didn’t want to figure out how to work it into a Docker container system, so I went old school and created a self-signed certificate. Please note you WILL need to add a “security exception” to your browser when you’re done with this process.

First off, you need openssl. I ~think~ I installed OpenSSL via Chocolatey install openssl on Windows, but honestly it was a while ago. You could also use the Openssl that comes in Ubuntu for Windows.

The command to create a self-signed cert is:

openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj "/C=US/ST=NC/L=Local/O=Dev/CN=mysite.local" -keyout ./ssl.key -out ./ssl.crt

First off, credit for this goes to StackExchange user THelper and in all honesty I don’t know exactly what all the parameters mean. (I’m so trusting!)

Here’s what you need to know to get this to work. ssl.key and ssl.crt are the filenames you’ll be generating. This string “/C=US/ST=NC/L=Local/O=Dev/CN=mysite.local” has to be customized:

/C = country code (I’m in the US)
/ST = state (North Carolina for me)
/L = locale… as you can see I fudged this
/O = Organization… again, fudged. All these matter if you’re creating a real cert to use online but for local.. meh
/CN = domain name. This one is important. I’m working on https://mysite.local

So edit that string and run the command and it should generate ssl.key and ssl.crt files.

I use docker-compose so I need to tweak my docker-compose.yml file to expose port 443 (the ssl port):

ports:
- 80:80
- 443:443

And in your dockerfile you need to copy the keys to your container. To do this, first drop them in the same directory as your docker file (I tried keeping them outside the directory but would get “Forbidden path outside the build context” errors).

Next, add this to your docker file:

RUN mkdir -p /etc/apache2/ssl/
COPY ./ssl.crt /etc/apache2/ssl/ssl.crt
COPY ./ssl.key /etc/apache2/ssl/ssl.key

So we’re creating a directory and copying the files into it.

Also remember to expose port 443 in your docker file:

EXPOSE 80
EXPOSE 443

Now you need to update your apache virtual hosts to support ssl.

Here’s part of my Virtual Host file, the first 3 lines are what we’re focused on, notice they match the directory we created in our docker file:

<VirtualHost *:443>
 SSLEngine On
 SSLCertificateFile /etc/apache2/ssl/ssl.crt
 SSLCertificateKeyFile /etc/apache2/ssl/ssl.key

ServerName mysite.local

ServerAdmin webmaster@localhost
 DocumentRoot /var/www/html

 ErrorLog ${APACHE_LOG_DIR}/error.log
 CustomLog ${APACHE_LOG_DIR}/access.log combined

<Directory "/var/www/html">
  Require all granted
  AllowOverride All
  Options Indexes FollowSymLinks
 </Directory>
 </VirtualHost>

And that should do it!