I’m not sure why WordPress doesn’t allow you to change the URL for the admin and login pages, but they don’t. It seems to me that putting define ( ‘ADMIN_PATH’, ‘/wp-admin/’ ); in wp-config would be an easy and a good fix–but for whatever reason, they don’t and we are stuck with a security hole.
I will first review the methods that currently exist as workarounds to this problem that we shouldn’t have in the first place, and then will go on to detail my method which I hope is a little easier to setup and maintain.
Plenty of methods exist for preventing access to these files, but IMO they are all overly complex, annoying, or flawed.
IP Limiting
I’ve never been a fan of limiting access based on IP unless it is really sensitive data. My reasoning here is that my IP is not static and it is a huge PITA to log in to my server and update my IP to give myself access again. Another problem with this approach is that it prevents you from accessing your blog while you’re anywhere but home. This method is not a good option for preventing access to wp-admin.
A WordPress Plugin
I just don’t like this solution. This means that each time a request is made to wp-admin, the entire WordPress code system needs to be loaded and executed before a request is allowed or denied. Plus it represents yet another thing you have to worry about maintaining and another possible vector of attack if the plugin itself has any kind of security holes. And as WP security has started to grow up, plugin security problems have become an increasingly common method for gaining control of your blog. Thanks, but no thanks Mr. stealth login plugin.
.htaccess Limiting
This solution is on the right track. It is a single file you can drop into any WP installation that will prevent access. It requires zero maintenance and allows you to “set it and forget it”. The problem with his solution is that it uses a sledge hammer when you need a scalpel ;]
Also, as the author states, this method prevents the “Edit” shortcut links from working.
My Solution
A specially crafted .htaccess file will allow you to “login” to the wp-admin section of your site by providing a keyword in the URL. If the keyword is missing, the visitor is automatically redirected to the homepage. If the keyword exists, a cookie is set on the machine that will allow access to wp-login.php and /wp-admin/ as you normally would.
This method requires no extra effort on your part beyond the .htaccess file and no modification to the WordPress code or install whatsoever.
RewriteEngine On
# Is this a request for wp-login?
RewriteCond %{REQUEST_URI} ^/wp\-login\..*
# Check for the secret word
RewriteCond %{QUERY_STRING} .*REPLACE_ME_WITH_A_SECRET_WORD=.*
# Set a cookie, so that all future requests will be auto-authenticated
RewriteRule ^.* /wp-admin/ [cookie=REPLACE_ME_WITH_A_SECRET_WORD:true:REPLACE_ME_WITH_YOUR_DOMAIN:3600:/,R,L]
# Is this a request to the admin?
# comment out this line and you will be able to reach wp-login.php, but not anything in /wp-admin/ until you authenticate
RewriteCond %{REQUEST_URI} ^/wp\-login\..* [OR]
RewriteCond %{REQUEST_URI} ^/wp\-admin/.*
RewriteCond %{HTTP_COOKIE} !\bREPLACE_ME_WITH_A_SECRET_WORD\b
# Unathenticated, redirect to homepage with a disallowed indicator
RewriteRule ^.* /?disallowed=true [R,L]
Setup:
- Replace REPLACE_ME_WITH_A_SECRET_WORD (3 occurrences) with a secret keyword. For reasons I won’t go into here, it is a good idea to stick with a keyword that contains only letters, numbers and underscores.
- Replace REPLACE_ME_WITH_YOUR_DOMAIN (1 occurrence) with your domain name like so: .example.com (note the first period but no www, this allows the cookie to function on any subdomain of your website)
- Optional: Change /?disallowed=true is the path the unauthorized visitor will be redirected to. You could also set it to “/” or any other page on your website.
- Optional: cookie=REPLACE_ME_WITH_A_SECRET_WORD:true:REPLACE_ME_WITH_YOUR_DOMAIN:3600:/ – 3600 is the number of minutes the cookie will remain cached. Feel free to make it lower but I suggest you keep it on the high side so that you won’t time out while working on your blog.
Getting it working:
Put all that into a file called .htaccess and put it in the root of your WordPress install. There may already be an .htaccess file there.
If there is already a .htaccess file there (there probably will be):
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
!!!!! INSERT THE NEW CODE HERE !!!!!
</IfModule>
# END WordPress
Save that file and now you will now be a little more secure.
Accessing The Admin
Let’s assume you made your secret word “k1tt3ns”. To “login”, you would visit http://blog.example.com/wp-login.php?k1tt3ns=true
If the phrase matches the one you set up in your .htaccess file, you should see the wp-login.php page like normal. A cookie will also have been set that will keep you “logged in” for however many minutes you set. After the cookie expires, you will have to “login” again by visiting http://blog.example.com/wp-login.php?k1tt3ns=true again.
Go ahead and try to log in to this site: http://www.mawhorter.net/wp-login.php. You won’t be able to, and instead, you will be redirected to this post.
This method allows you to bookmark your login page like normal, and will keep bad people from easily accessing it.
Drawbacks:
Cookies must be enabled. I can’t think of any others? Anyone?

Great post. I was wondering….. I have a site that is restricted to the public (unless you are a WP member of the site). But I’ve noticed that you can access FILES directly even if you are not a member (e.g. http://site.com/wp/uploads/something.pdf). Is there a way for ALL content to redirect to the login page if you aren’t logged in?
Thanks!
Reply
Cory reply on January 27th, 2010 17.49.39:
There are ways, but they’re all pretty cumbersome or flawed. ATM, the best way I can think of is to wrap all content in PHP.
* You would use mod_rewrite to check if the user is requesting something in ^/wp-uploads/.* (That’s a regex that detects if anything in the folder of wp-uploads or below is being requested.
* All the requests would then be redirected to a file that you would need to create in your site root, let’s call it binauth.php
So… using your example and mod_rewrite rules that I leave it up to you to create, a request to wp-uploads/something.pdf would be redirected to http://site.com/binauth.php?path=wp-uploads/something.pdf
This file would then use WP’s internal functions to determine if the user has been properly authenticated. At this point, you would know the file they are requesting, along with if they are logged in and authorized to view the content.
You could then do one of two things:
1. Issue the proper headers (like Content-type) for the file, and use PHP’s readfile to send it to the user. (This is the only way to do it securely)
2. Redirect the user to the file at auth-uploads/something.pdf You would then have to create a rewrite rule that detects and directs these requests to the correct location internally. This is NOT secure, but would prevent the average user from being able to access your files.
If the user is not logged in, you would issue a 403 (not authorized) error, and they wouldn’t see your files.
You would also probably want to set up a rule in robots.txt to prevent spiders from even trying to access your files:
User-agent: *
Disallow: /wp-uploads/*
Disallow: /auth-uploads/*
There is probably a WP plugin out there to do this automatically. I didn’t bother searching.
Reply
Jim reply on July 20th, 2010 15.05.25:
FYI, most spiders skip the rules in robots.txt or do even use the info there to index your precious posts…
This is a better idea: http://perishablepress.com/press/2010/07/14/blackhole-bad-bots/
Reply
Hey, great job!! I’ve been trying to mess with other htaccess files and they’re just not as clean and simple as the method you came up with! One time I didn’t realize I wasn’t getting comments because of the htaccess file was blocking whenever someone tried to post a comment. I also wanted to ask a question, the wp-includes directory by default is listed by going to domain.com/wp-includes… dropping a blank index.php or html file will suffice restricting access right? putting Options -Indexes in the htaccess file would effectively do the same thing, correct?
Reply
Cory reply on March 8th, 2010 19.50.49:
Hey Lee. Sorry I missed your comment!
> dropping a blank index.php or html file will suffice restricting access right? putting Options -Indexes in the htaccess file would effectively do the same thing, correct?
Absolutely right. Whenever I make something from scratch, I’ve just got in the habit of creating blank index.html files. You never know if the server your code is going to run on will have indexes disabled or even index.php configured to be an directory index.
Options -Indexes is a good idea to use server wide if you have files that should stay hidden, but it should also work with .htaccess. http://httpd.apache.org/docs/1.3/mod/core.html#options
It is generally considered a better idea to store any files that shouldn’t be listed outside of webroot if at all possible. Things like database connection credentials and whatnot — or a directory of porn that you’ve been squirreling away on the company webserver. You know, the usual stuff.
Reply
Interesting: but what permissions should be set for the .htaccess file? If set to 644, anyone can read it, which rather defeats the point of the exercise…
Reply
Cory reply on March 8th, 2010 18.41.01:
Hi Donald. Your apache config should be set to disallow serving of all dot files. (.htaccess, .htpasswd etc). I think most flavors of apache installs come preconfigured this way.
I’m not sure that prohibiting access to your htaccess file is a concern from the filesystem side of things? Do you disagree? I’d be more concerned about disallowing access to wp-config.php and your DB login and pw.
Reply
@Cory: Yes, you’re right, my server certainly blocks all access to dot files. My concern was just that the secret word, in your solution, is included in the htaccess file, so somehow people might be able to read it if they _did_ gain access. An extra layer can be added by including the following:
# secure htaccess file
order allow,deny
deny from all
Reply
Cory reply on March 8th, 2010 19.36.30:
Ahh… I see where you’re coming from.
Just for completeness for the generations to come, the following will prevent access to .ht* files:
<FilesMatch "^\.ht"> Order allow,deny Deny from all </FilesMatch>You would put that in your httpd.conf as its own directive.
edit: Removed “satisfy all”. It is included with wamps httpd.conf, but not necessary because this is the default setting for apache.
Reply
I love your version! Have just set up my own self-hosted WordPress blog and have read up on security – was just about to go with the IP limiting before accidentally stumbling over this post.
I tried to set this up in my htaccess but for some reason it’s not working. I copied your code and replaced the capital letters with my own stuff, have tried many times with different keywords – no success – instead I end up on the front page. Any ideas why?
Reply
Hi Cory,
this is what I was looking for! :)
Had a lot to google!
As I am not very experienced in writing htaccess-files.
How would the sample look like, if I would have my blog in a subdirectory of my domain like /blog/ and the blog would be visible by visiting
http://www.mydomain.com/blog/
and where would I have to put the htaccess-file?
In the root-folder?
All the best
Mark
Reply