Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: administration

  • WordPress Login Protection with ModSecurity

    WordPress Login Protection with ModSecurity

    No ModSec? Check out WordPress Login Protection With .htaccess

    LockIf you’re on Liquid Web servers, this was already done for you. If you’re not, you should still be able to use this code on your own ModSecurity instance. Since this is a way better method to block people than via a plugin, in my opinion, I thought it would be a good idea to share it here. With this rule, you won’t have quite as many http requests.

    WordPress is a popular publishing platform which is known for its robust features, numerous templates, and large support community. Unfortunately, due to such popularity, WordPress is also constantly subject to attempts at exploiting vulnerabilities. Ensuring WordPress and any associated plugins are installed with the most current versions is an important means of securing your site. However, ModSecurity provides a significant amount of further security by providing an application firewall.

    ModSecurity (also known as “modsec”) has proven itself useful in a variety of situations, and again this is true in assisting with WordPress brute force attempts resulting in a Denial of Service (DoS) attack. While a number of WordPress plugins exist to prevent such attacks, custom modsec rules can prevent such attacks for all WordPress installations on a server. Modsec immediately filters incoming HTTP requests, which assists against taxing server resources.

    These rules will block access for the offending IP address for 5 minutes upon 10 failed login attempts over a 3 minute duration. These rules have been automatically updated in the custom rules for Liquid Web’s ServerSecure service. For customers without ServerSecure, these rules can be added to their custom modsec rules. To accomplish this, edit your custom modsec user rules and append the file with the rules provided below. For CPanel servers, this file is likely located at /usr/local/apache/conf/

    SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},initcol:user=%{REMOTE_ADDR},id:5000134
    <Locationmatch "/wp-login.php">
        # Setup brute force detection.
    
        # React if block flag has been set.
        SecRule user:bf_block "@gt 0" "deny,status:401,log,id:5000135,msg:'ip address blocked for 5 minutes, more than 10 login attempts in 3 minutes.'"
    
        # Setup Tracking.  On a successful login, a 302 redirect is performed, a 200 indicates login failed.
        SecRule RESPONSE_STATUS "^302" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000136"
        SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000137"
        SecRule ip:bf_counter "@gt 10" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0"
    </locationmatch>
    

    Source: Liquidweb and Frameloss and MNX Solutions

    Logically, someone can extend this code to any file, like bb-login.php or Special:UserLogin, depending on where they’re being hacked.

    ETA: Rarst asked if I’d have to use wildcards with Locationmatch since WP is often in a subfolder. I read the Apache doc on locationmatch and it says that it’s using regex, so it should just look for ‘/wp-login.php’ in the URL. If I wanted to only look for example.com/wp-login.php then I’d use ^wp-login.php instead. If I got that wrong, please let me know!

  • Collecting Conflicting Stats

    Collecting Conflicting Stats

    StatisticsWhile, like many people, I use Google Analytics, I don’t really trust it’s parsing. I do use mod_pagespeed which lets me auto-embed my GA code in every page without plugins or extra work on my part, which is great, but the results are questionable and often wildly disparate and conflicting.

    Let me demonstrate:

    Google AWStats Webalizer
    Page views 2,607 10,354 8,502
    Hits 49,830 59,542
    Visits 888 1,274 2,255

    First of all, I can’t find ‘hits’ anywhere on Google. Their layout is different and changes regularly. Secondly, and I’m sure this jumps out at you, according to AWStats and Webalizer, I’m getting 4 to 5 times the pageviews compared to Google. I previously configured AWStats and Webalizer to exclude wp-admin and other ‘back end’ pages by editing the configuration files. I did the same in my .htaccess for PageSpeed, so I know no one is tracking admin pages.

    I already know that AWStats errs on the site of users, so if it can’t tell something is a bot, it assumes it’s a user. I also know it tends to overcount, since it bases its counts on traffic in a way that is a little generous (a 60 minute count for a visit). Not a huge deal, but enough to say that yes, the 10k pageview is probably closer to the 9 or 8 of Webalizer. Speaking of Webalizer, it uses a 30 minute count, so there it skews higher. Fine, let’s be harsh and halve them.

    That gives me 4000-ish pageviews. Google gave it 2600-ish.

    Interestingly, Google gives a 30 minute visit count too, but it also uses cookies and javascript, which while fairly safe, doesn’t run on everyone’s browser. As an amusing side-bar, when I switched from using a plugin or manually injecting Google Analytics into my sites and started using mod_pagespeed’s insertion, my results went up. Noticeably. In part this is attributed to the fact that my site is having higher traffic than normal, but when I compared it to WordPress Stats, it was a bigger than expected jump.(I’m not using WordPress’s Stats ala Jetpack in this experiment because it only counts WordPress pages, and the site I’m using is not just WP. However on a pure WP site, WP’s stats tend to skew higher than GA.)

    Which one is right? Most people will say Google is ‘closer to the truth’ but I don’t know how much I can rely on that. Certainly it’s more true for how many actual people are visiting my site, and when I’m judging metrics for marketing, I’m a little more inclined to use Google. That said, if I’m trying to understand why my page speed is slow, or where I’m getting hammered with traffic, AWStats and Webalizer are far more accurate, since they’re counting everything.

    Data that can, and cannot, be measured
    From “Manga Guide to Statistics,” Shin Takahashi, 2008
    Right now, I’m keeping Google Analytics on my sites. I don’t really need the measurements for marketing (that would involve doing marketing), but there are better social engagement stats provided that make it helpful. Like of all the social media sites, Facebook and Twitter are tied for traffic, and Google Plus is only high scored on my tech blog. I think that if Google let us auto publish to Google+, those stats would change, but for now, it’s all manual.

    This is not to say that I think auto-posting is great for social engagement, but I find I actual pay attention more to the social aspect of the media if I don’t have to remember to post all over the place. This is a massive shift since October 2011, when I’d stopped auto-posting for SEO reasons. Why did I change my stance? Well it because easier to autopost and keep that personal touch with Jetpack’s Publicize feature. Now I can easily insert a custom message, and I know it’s going to (mostly) use my excerpt.(For some reason Tumblr is a moron about this) That saves me effort and allows me to spend more time actually interacting!

    Auto-generating my stats with little effort, and being able to easily read them without needing a degree in SEO (no they don’t exist) is also hugely important. Google Analytics is easy to read, but curiously I find it overly complicated to understand. The different pages and layouts make it surprisingly hard to find ‘What were my stats for yesterday?’ Sometimes I have a boom in traffic on one day (like the day I had a 600% increase) and I want to see what went on and why. Where was this traffic coming from? WordPress’s stats do this amazingly well, just as an example.

    No one tool provides all the data I need to measure all aspects of my site, nor does anyone one tool collect all the data. Google tells me more about browser size, screen resolution, and everything it can grab about the user, where AWStats and Webalizer give me more information about traffic by showing me everything, bots and humans. Basically server tools are great for collecting server stats, and webpage tools are great for user stats. But you need both.

    So in the end, I have at least four different statistic programs I check on, regularly, to try and understand my traffic and measure success.

  • Cacheless (or not)

    Cacheless (or not)

    ETA: As of a month later, I’ve actually switched from APC to Zend Optimizer+

    FilesDon’t get me wrong, I love caching. I love W3 Total Cache (I’m willing to spend my ‘free time’ testing it, after all), and WP Super Cache saved my life once. So why, on a day where I got a 400-600% uptick in traffic (not a joke), did I turn all my caching off? I’m daring, and a little crazy, but I wanted to see if it could be done. I would not have tried this if I was on a smaller server: if you’re getting as much traffic as I am, and you’re on shared hosting, you really need to move to a VPS or Dedicated Server if you want to turn off caching via plugins. It’s not to say that caching is better or worse than not-caching, or vice versa, or that one is a rich-man/poor-man equivalent of the other. Caching plugins are an inexpensive way to speed up your site, and if you can’t afford a bigger server they will buy you the time you need to figure out a better solution. Even with a good plugin and setup, if you get hammered with a lot of traffic, you will crash your site unless the server’s optimized too. Again, what I’ve done is not something I’d try on a low-end server with high traffic.

    When I started measuring the effectiveness of all this, I used:

    To understand what caching is and why we use it, it’s good to understand the basic concepts, and to start by looking at what caching plugins are, how they work, and where their pitfalls are.

    • There are parts of your website that don’t change often (images, javascript, CSS, etc).
    • You want the user to only download what’s changed.

    That sounds easy, but WordPress isn’t static HTML, it’s PHP, and that means every time you visit the page, it runs various proceses to give you the latest and greatest files. The problem with this dynamic code is where content changes rapidly (think ‘comments’ or ‘forums’ or ‘BuddyPress Groups’). Suddenly caching ‘pages’ as wholesale chunks of html doesn’t help if you have to re-cache when someone leaves a remark. Add in the possibility of 4 or 5 people commenting at once, for 12 hours, and now you’re risking a thrashing situation where you keep trying to cache, but it keeps flushing. This is why most people use plugins that handle things elegantly, or try to, where the ‘static’ part of the page (sidebar, etc) are HTMLized, but the dynamic part is left alone. This helps when you have a portion of every page is dynamic, like a shopping cart with a ‘Your order…’ box.

    StorageBut the downside is that you have to write fancy code that remains dynamic portions, and while it certainly can be done, it’s not fun, and let’s be honest, a theme developer doesn’t know which cache you’re going to use, so how can it write the right way for that? The only way to make a truly dynamic and cachable site is to do it from day one, with your theme, server, and plugins all crafted to provide the best experience. And then we have reality, which is we start with something simple, wake up to something large, and experience growing pains.

    Accepting the fact that we’re not starting from nothing, that we have an existing site with content and activity, the first thing most people do is install a plugin. Now, back to what I said before, this isn’t a bad thing. It’s a good first step and will buy you time. It’ll also show you where you need to go. If you don’t have server root access, this may be a your limit, too, as some of the other things I like to do to speed things up without a cache will require it (or you’ll have to ask your hosts and they may tell you to upgrade).

    If you’re going to use a plugin, WP Super Cache (WPSC) and W3 Total Cache (W3TC) are the best two. W3TC is way more advanced, and has a lot of extra bells and whistles, but personally I find that once you can master it, you’re well on your way. Remember though, you’re sacrificing a lot of control here by using a plugin. They’re going to, by their nature, cache everything they can, and we’re back to where we were with the dynamic site generation issue. W3TC has a bunch of extra .htaccess/nginx rules which parse data before you hit WordPress. WPSC can do that, or use PHP (which is slower).

    The dynamic nature of my site is what drove me away from caching plugins. I use other CMS tools, and for my infrequently updated Wiki and ZenPhoto Gallery, where content is very much static, caching makes perfect sense. But when I want to run a simple community site with WordPress, I have to consider all aspects of user experience. Speed is hugely important, but so is the user getting the content they want. Stale content is a killer.

    The reason I decided to see if my site ran slower without caching was that I was reinstalling caching and I thought “This is a perfect time to benchmark.” When I did I was astounded. There was very little difference in a benchmark test. Really no difference between at all, since it was within the results of each other, but I neglected to save the results at the time. I did however snap a picture of my server load(The unrelated part is where I was uploading 10megs of media. Unrelated.):

    load-graph

    Browser Caching is the first thing to tweak, as that tells browsers to cache content. The way this works is your .htaccess tacks on extra information while content like images and CSS are being downloaded, to say “This content is good for X days.” With WordPress, you don’t have to worry about changing the CSS, as most themes and plugins are extra smart, in that they append a version to the end of your CSS like this: style.css?ver=1.9.1 That 1.9.1 is the version of Genesis I’m running, so when that changes, the version changes, and browsers see it as a new file and re-download. That’s pretty cool. (I do wish that child themes pulled in their version, so you could increment that way.) We still have to tell the broswers to cache, and for how long, so near the top of my .htaccess (just below my hotlink protection) I have this:

    ## BEGIN EXPIRES ##
    
        ExpiresActive On
        ExpiresByType image/jpg "access 1 year"
        ExpiresByType image/jpeg "access 1 year"
        ExpiresByType image/gif "access 1 year"
        ExpiresByType image/png "access 1 year"
        ExpiresByType image/x-icon "access 1 year"
    
        ExpiresByType text/css "access 1 month"
        ExpiresByType text/html "access 1 hour"
    
        ExpiresByType application/pdf "access 1 month"
        ExpiresByType application/x-javascript "access 1 month"
        ExpiresByType application/javascript "access 1 month"
        ExpiresByType text/javascript "access 1 month"
        ExpiresByType text/x-js "access 1 month"
    
        ExpiresByType application/x-shockwave-flash "access 1 month"
        
        ExpiresByType video/quicktime "access 1 month"
        ExpiresByType audio/mpeg "access 1 month"
        ExpiresByType video/mp4 "access 1 month"
        ExpiresByType video/mpeg "access 1 month"
        ExpiresByType audio/ogg  "access 1 month"
        ExpiresByType video/ogg  "access 1 month"
    
        ExpiresDefault "access 2 days"
    
    ## END EXPIRES ##
    

    I’ve added in only the types used by my site. I used to use Pragma caching headers as well, but I noticed that Google PageSpeed Insights and YSlow ignore them. Turns out that Pragma headers aren’t honored all the time, in fact, they aren’t honored often, so I just removed them. I don’t think it slowed my site down to have them, but the less to maintain, the better. This had an immediate positive impact, so it was time to look at the server.

    ShapesOver the years, I’ve tuned httpd.conf so it doesn’t crash, I’ve got CSF locked down to prevent people from DoS’ing me over TimThumb, and I of course have APC turned on. Recently I broke down and installed mod_pagespeed when I upgraded to PHP 5.4. Just those things have done a lot to make my site run faster. I intentionally skipped things like Varnish or TrafficServer, as well as a CND or Google’s PageSpeed Service. I (still) don’t need them.

    Since I’m new to Page Speed, I decided to look deep into the filters and enabled the following for the whole server: rewrite_javascript, rewrite_css, collapse_whitespace, elide_attributes. This had a right-away impact of what I jokingly called ‘Effective Minification.’ These filters are new to me, so I spent a lot of time reading up on all the filters, and I find them highly interesting. By having PageSpeed handle things like offloading jQuery, I take the load off of WordPress and other CMS tools, and don’t have to use a plugin.(Don’t get the wrong idea. There are uses for plugins! But I’m all about using the right tool for the right job. I don’t have plugins handle my WordPress database, because I feel it’s like using a screwdriver to hammer in a nail. You can….)

    I added in a couple more to my standard: remove_comments and rewrite_images. Then I went back to my site’s .htaccess and started turning on the things I wanted per-site.

    The ones I picked are:

    Putting those in my .htaccess looks like this (note: no spaces between the filter names, or it all blows an error 500):

    
        ModPagespeedEnableFilters move_css_to_head,defer_javascript,insert_ga
        ModPagespeedAnalyticsID UA-MYCOOLID-1
    
    

    That also means I don’t have to use a plugin to use Google Analytics for my whole site! This may not mean a lot to you, but I have multiple ‘apps’ on my site (four now) and when I edit themes, if I don’t have to do anything, it’s easier. Google will tell you not to do this, but unless they have a way for me to set pagespeed.conf in the /home/user/ folder of my server, I don’t know another per-user way about this.

    Finally I went back on my word, and I installed a plugin. APC by Mark Jaquith. This isn’t a full reversal on my ‘No Plugins!’ stance before, though. All APC is, you see, is but one file that sites in wp-content and kicks things over to APC. Doing this alone moved my TTFB from an F to a B. Which is pretty impressive. Giving it a little time to bake, this worked out okay.

  • CentOS and PHP 5.4

    CentOS and PHP 5.4

    PHP ElephantsI finally got around to PHP 5.4

    Alas this meant reinstalling certain things, like ImageMagick and APC.

    This also brought up the question of pagespeed, which I keep toying with. I use it at work, but since this server’s on CentOS with EasyApache, there’s no ‘easy’ way to install PageSpeed yet (not even a yum install will work), so it’s all manual work plus fiddling. I don’t mind installing ImageMagick and APC, but Google’s own ‘install from source’ aren’t really optimized for CentOS, even though they say they are, and I’m nervous about the matter. Well… I did it anyway. It’s at the bottom.

    The only reason I had to do this all over is that I moved to a new major version of PHP. If I’d stayed on 5.3 and up’d to 5.3.21, that wouldn’t have mattered. But this changed a lot of things, and thus, a reinstall.

    ImageMagick

    ImageMagick I started using ImageMagick shortly after starting with DreamHost, since my co-worker Shredder was working on the ‘Have WP support ImageMagick’ project. It was weird, since I remembered using it before, and then everyone moved to GD. I used to run a photo gallery with Gallery2, and it had a way to point your install to ImageMagick. Naturally I assumed I still had it on my server, since I used to (in 2008). Well since 2008, I’ve moved servers. Twice. And now it’s no longer default.

    Well. Let’s do one of the weirder installs.

    First you install these to get your dependancies:

    yum install ImageMagick
    yum install ImageMagick-devel
    

    Then you remove them, because nine times out of ten, the yum packages are old:

    yum remove ImageMagick
    yum remove ImageMagick-devel
    

    This also cleans out any old copies you may have, so it’s okay.

    Now we install ImageMagick latest and greatest from ImageMagick:

    cd ~/tmp/
    wget http://imagemagick.mirrorcatalogs.com/ImageMagick-6.8.1-10.tar.gz
    tar zxf ImageMagick-6.8.1-10.tar.gz
    cd ImageMagick-6.8.1-10
    ./configure --with-perl=/usr/bin/perl
    make
    make install
    

    Next we install the -devel again, but this time we tell it where from:

    rpm -i --nodeps http://www.imagemagick.org/download/linux/CentOS/x86_64/ImageMagick-devel-6.8.1-10.x86_64.rpm
    

    Finally we can install the PHP stuff. Since I’m on PHP 5.4, I have to use imagick-3.1.0RC2 – Normally I’m not up for RCs on my live server, but this is a case where if I want PHP 5.4, I have to. By the way, next time you complain that your webhost is behind on PHP, this is probably why. If they told you ‘To get PHP 5.4, I have to install Release Candidate products, so your website will run on stuff that’s still being tested,’ a lot of you would rethink the prospect.

    cd ~/tmp/
    wget http://pecl.php.net/get/imagick-3.1.0RC2.tgz
    tar zxf imagick-3.1.0RC2.tgz
    cd imagick-3.1.0RC2
    phpize
    ./configure
    make
    make install
    

    Next, edit your php.ini to add this:

    extension=imagick.so
    

    Restart httpd (service httpd restart) and make sure PHP is okay (php -v), and you should be done! I had to totally uninstall and start over to make it work, since I wasn’t starting from clean.

    Speaking of clean, cleanup is:

    yum remove ImageMagick-devel
    rm -rf ~/tmp/ImageMagick-6.8.1-10*
    rm -rf ~/tmp/imagick-3.1.0RC2*
    

    APC

    APCI love APC. I can use it for so many things, and I’m just more comfortable with it than xcache. Part of it stems from a feeling that if PHP built it, it’s more likely to work. Also it’s friendly with my brand of PHP, and after 15 years, I’m uninclined to change. I like DSO, even if it makes WP a bit odd.

    Get the latest version and install:

    cd ~/tmp/
    wget http://pecl.php.net/get/APC-3.1.14.tgz
    tar -xzf APC-3.1.14.tgz
    cd APC-3.1.14
    phpize
    ./configure
    make
    make install
    

    Add this to your php.ini:

    extension = "apc.so"
    

    Restart httpd again, clean up that folder, and then one more…

    mod_pagespeed

    mod_pagespeedI hate Google. Well, no I don’t, but I don’t trust them any more than I do Microsoft, and it’s really nothing personal, but I have issues with them. Now, I use PageSpeed at work, so I’m more comfortable than I was, and first I tried Google’s installer. The RPM won’t work, so I tried to install from source, but it got shirty with me, fast, and I thought “Why isn’t this as easy as the other two were!?” I mean, APC was stupid easy, and even easier than that would be yum install pagespeed right?

    Thankfully for my sanity, someone else did already figure this out for me, Jordan Cooks, and I’m reproducing his Installing mod_pagespeed on a cPanel/WHM server notes for myself.(By the way, I keep a copy of this article saved to DropBox since invariably I will half-ass this and break my site.) Prerequisite was to have mod_deflate, which I do.

    The commands are crazy simple:

    cd /usr/local/src
    mkdir mod_pagespeed
    cd mod_pagespeed
    wget https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-beta_current_x86_64.rpm
    rpm2cpio mod-pagespeed-beta_current_x86_64.rpm | cpio -idmv
    cp usr/lib64/httpd/modules/mod_pagespeed.so /usr/local/apache/modules/
    chmod 755 /usr/local/apache/modules/mod_pagespeed.so
    mkdir -p /var/mod_pagespeed/cache
    chown nobody:nobody /var/mod_pagespeed/*
    

    Once you do this, you have to edit the file, and this is where I differ from Jordan’s direction. He just copied this over /usr/local/apache/conf/pagespeed.conf but I had an older version from a ‘Let’s try Google’s way….’ attempt and someone else’s directions, so I made a backup and then took out the ModPagespeedGeneratedFilePrefix line since I know that’s deprecated. I also added in a line to tell it to ignore wp-admin.

    Here’s my pagespeed.conf (edited):

    LoadModule pagespeed_module modules/mod_pagespeed.so
    
    	# Only attempt to load mod_deflate if it hasn't been loaded already.
    <IfModule !mod_deflate.c>
    	LoadModule deflate_module modules/mod_deflate.so
    </IfModule>
    
    <IfModule pagespeed_module>
    	ModPagespeed on
    
    	AddOutputFilterByType MOD_PAGESPEED_OUTPUT_FILTER text/html
    
    	ModPagespeedFileCachePath "/var/mod_pagespeed/cache/"
    
        ModPagespeedEnableFilters rewrite_javascript,rewrite_css
        ModPagespeedEnableFilters collapse_whitespace,elide_attributes
        ModPagespeedEnableFilters rewrite_images
        ModPagespeedEnableFilters remove_comments
    
    	ModPagespeedFileCacheSizeKb 102400
    	ModPagespeedFileCacheCleanIntervalMs 3600000
    	
    	# Bound the number of images that can be rewritten at any one time; this
    	# avoids overloading the CPU. Set this to 0 to remove the bound.
    	#
    	# ModPagespeedImageMaxRewritesAtOnce 8
    
    	<Location /mod_pagespeed_beacon>
    		SetHandler mod_pagespeed_beacon
    	</Location>
    
    	<Location /mod_pagespeed_statistics>
    		Order allow,deny
    		# You may insert other "Allow from" lines to add hosts you want to
    		# allow to look at generated statistics. Another possibility is
    		# to comment out the "Order" and "Allow" options from the config
    		# file, to allow any client that can reach your server to examine
    		# statistics. This might be appropriate in an experimental setup or
    		# if the Apache server is protected by a reverse proxy that will
    		# filter URLs in some fashion.
    		Allow from localhost
    		Allow from 127.0.0.1
    		SetHandler mod_pagespeed_statistics
    	</Location>
    
    	ModPagespeedMessageBufferSize 100000	
    	ModPagespeedDisallow */wp-admin/*
    	ModPagespeedXHeaderValue "Powered By mod_pagespeed"
    
    	<Location /mod_pagespeed_message>
    		Allow from localhost
    		Allow from 127.0.0.1
    		SetHandler mod_pagespeed_message
    	</Location>
    	<Location /mod_pagespeed_referer_statistics>
    		Allow from localhost
    		Allow from 127.0.0.1
    		SetHandler mod_pagespeed_referer_statistics
    	</Location>
    </IfModule>
    

    To tell Apache to run this, edit /usr/local/apache/conf/includes/pre_main_global.conf and add:

    Include conf/pagespeed.conf

    Note: We put this code here because EasyApache and httpd.conf will eat your changes.

    Finally you rebuild Apache config and restart apache and test your headers to see goodness! My test was a success.

    HTTP/1.1 200 OK
    Date: Mon, 21 Jan 2013 03:12:13 GMT
    Server: Apache
    X-Powered-By: PHP/5.4.10
    Set-Cookie: PHPSESSID=f4bcdae48a1e5d5c5e8868cfef35593a; path=/
    Cache-Control: max-age=0, no-cache
    Pragma: no-cache
    X-Pingback: https://ipstenu.org/xmlrpc.php
    X-Mod-Pagespeed: Powered By mod_pagespeed
    Vary: Accept-Encoding
    Content-Length: 30864
    Content-Type: text/html; charset=UTF-8
    

    For those wondering why I’m ignoring wp-admin, well … sometimes, on some servers, in some setups, if you don’t do this, you can’t use the new media uploader. It appears that PageSpeed is compressing the already compressed JS files, and changing their names, which makes things go stupid. By adding in the following, I can avoid that:

    	ModPagespeedDisallow */wp-admin/*
    

    Besides, why do I need to cache admin things anyway, I ask you?

    So there you are! Welcome to PHP 5.4!

  • Multisite Login Loop

    Multisite Login Loop

    Congratulations, you’ve decided to go Multisite and added in all your lines to your config file. You’re raring to go, and the last step is to log out and back in.

    But you can’t.

    You get to the login screen, enter your credentials, and the page just refreshes. What’s on earth is going on?

    This is actually a pretty rare thing, and I was only able to reproduce it when I moved my site on the server. The fix is actually pretty easy, and there are three things to do.

    1) Edit your wp-config.php.

    Visit https://api.wordpress.org/secret-key/1.1/salt/ and get new salts/hashes. This should prompt your users to re-login and hopefully generate new cookies.

    2) Dump your cache.

    Sometimes, however, browsers are idiots and you have to flush the local cache. You shouldn’t need to dump caching plugins, since that doesn’t impact logins.

    3) Delete your cookies.

    I hate this one. Delete the cookies only for your domain if possible. Chrome hides this, but it’s doable for all sites.

    4) Check your .htaccess

    A lot of people miss this. When the directions say ‘Replace your .htaccess with this…’ what they mean is replace. And yet many people leave in the old WordPress rules. Remember to replace your .htaccess calls for WP with the correct one: Multisite .htaccess rules

    5) Check your wp-config.php again

    You need to have both define('WP_ALLOW_MULTISITE', true); and define('MULTISITE', true); in there.

    But what if you have this problem on Single Site? Do the same thing, but if you’re using CloudFlare, go check your settings. They’ve been known to cause problems with this, due to handling of redirects. Me and a coworker wasted a couple hours on that, before someone else pointed it out.

    Edited to add….

    6) Kick wp-config.php in the butt

    Tom McFarlin came up with added this to your file:

    define('ADMIN_COOKIE_PATH', '/');
    define('COOKIE_DOMAIN', '');
    define('COOKIEPATH', '');
    define('SITECOOKIEPATH', '');
    

    This kicks the cookies.

  • Auto Multisite Registration

    Auto Multisite Registration

    There are plugins for this, and I’m rather fond of them. If you just want all new users to be added to some (or all) sites, then I suggest you use Multisite User Management. It’s a great plugin, and lets you pick and chose. But similar to how sometimes you want users to register per site, you may have a situation where you want users to be added to any and all sites when they visit.

    So how do we do this? It’s really not that painful, just make a add-users.php file in your mu-plugins folder with this:

    <?php
    
    /*
    Plugin Name: Add Users
    Description: Add users to blogs when they visit.
    */
    
    function helf_add_users( ) {
        global $current_user, $blog_id;
    
        if(!is_user_logged_in())
        return false;
     
        if( !is_user_member_of_blog() ) {
            add_user_to_blog($blog_id, $current_user->ID, "subscriber");
        }
    }
    
    add_action( 'wp' , 'helf_add_users' , 10);
    

    This code will automatically detect “John Doe is logged in.” and “John is not a member of this site.” If both of those are true, then it says “We will add him as a subscriber.” You can change subscriber as you see fit.

    Would it be more efficient to just do this check on registration? Sure. But there are moments you don’t want this. If you wanted to get extra sneaky, you could set this to only run on a specific page, and make that page password protected.

    If we want to add in a couple extra layers, that’s also not terrible. Let’s say we want people to press a button ‘Join This Site’? I have to admit, this actually took me longer to hash out than I wanted it to, mostly because I decided if I was going to do this, I should do it all the way.

    That’s why I came up with Join My Multisite, which is a handy plugin to give you some more options. It’s per-site configurable, so your site-admins will get to decide if they want everyone logged in user to be added to their site, or if they want a widget, or if they want nothing at all. I put some time into thinking about if it would be a good idea to have the network admin be able to pick, but when I got down to brass tacks, I realized there was no way to easily force a widget (i.e. the button to join the site) for all sites and make it always look good. If you need that, you should fork the plugin and hard-code in the widget.

    Join or Die

    In a way, this is an extension of the old ‘Add Users Sidebar’ plugin, which drifted off into the wayward lands of not-supported. I never looked at that code, though, and instead wrote all this from scratch.

    In addition to all that, Join My Multisite gives each site the ability, if registration is open, to easily make a per-site registration page. That one was Mason James’ suggestion.