Creating a private website with WordPress

When we became parents in 2015, Kelly and I talked about where and how we wanted to share the initial photos and stories of that experience with a small group of our family and friends. In case you haven't noticed, I feel pretty strongly about the principle of owning our digital homes. So I felt resistance to throwing everything up on Facebook in hopes that we'd always be able to make their evolving privacy and sharing settings and policies work for us, while also trusting that every single Facebook friend would honor our wishes about re-sharing that information.

I took some time to explore tools available for creating a private website that would be relatively easy for our users to access, relatively easy to maintain, and still limited in how accessible the content would be to the wider world. (I tend to assume that all information connected to the Internet will eventually become public, so I try to avoid ever thinking in terms of absolute privacy when it comes to websites of any kind.)

I thought about using WordPress.com, which offers the ability to quickly create a site that is private and viewable only by invited users while maintaining full ownership and control of the content. I passed on this idea in part because it didn't allow quite the level of feature customization that I wanted, and partly because it's a service of my employer, Automattic. While I fully trust my colleagues to be careful and sensitive to semi-private info stored there, it felt a little strange to think of creating something a bit vulnerable and intended for a small group of people within that context. I would still highly recommend the WordPress.com option for anyone looking for a simple, free/low-cost solution to get started.

Here are the WordPress tools I ended up using, with a few notes on my customizations:

Basic WordPress Configuration

For the basic WordPress installation and configuration, I made the following setup choices:

  • I put the site on a private, dedicated server so that I had control over the management and maintenance of the site software (as opposed to a shared server where my content, files or database may be accessible to others).
  • I used a Let's Encrypt SSL certificate and forced all traffic to the SSL version of the site, to ensure all communication and access would be encrypted.
  • I set up a child theme of a default WordPress theme so I could add a few customizations that would survive future parent theme updates.
  • I set "Membership" so that "Anyone can register" in the role of Subscriber (see more below on why this is okay).
  • For Search Engine Visibility I set "Discourage search engines from indexing this site".
  • For discussion I set "

My Private Site Plugin

The My Private Site plugin (originally JonRadio Private Site) is a great start for creating a self-hosted private WordPress site. It lets you set things up so that all content on your site is always private to registered users. Users can self-register (possibly using a custom login page you create), login and be redirected to a location of your choosing. You can exclude some content from being private (an introduction page, maybe?) or not. And it has a few other features that are really great.

(A simple alternative plugin is Password Protected, but doesn't fit with some of the other things I wanted to do and it uses a single password for everyone who accesses your site, creating potential hassle if you decide you need to change the password later.)

New User Approve Plugin

The New User Approve plugin is an important complement to the My Private Site plugin, in that it allows a site administrator to approve new user registrations before they become active. In our case we wanted to make sure that our site was only available to the small group we invited, and couldn't be accessed just because a random stranger on the Internet took the time to set up a username and password.

User Registration Approval admin interface in wp-admin

I used the helpful filters and hooks provided by this plugin to change some of its functionality:

  • Filter new_user_approve_welcome_message to change the message above the login box on the front page of the site, making it a little more welcoming than the default for this particular case.
  • Filter new_user_approve_register_instruction to clarify what the user should do in choosing a username and password.
  • Filter new_user_approve_pending_message to clarify that the user should wait for a confirmation/approval message before logging in.
  • Filter new_user_approve_approve_user_subject to change the subject line of the confirmation/approval message.
  • Filter new_user_approve_approve_user_message_default to change the body of the confirmation/approval message.
  • Removed action new_user_approve_deny_user to avoid sending email to any user whose registration is denied.

Simple New Post Emails Plugin

The Simple New Post Emails plugin is outdated and apparently unmaintained (see my aging Pull Request), but still works fine for my needs. Instead of other plugins and tools for sending new post notifications that might require syncing the site content to an external service and/or delivering the post content in the email message body, SNPE can be set up to provide a simple check-box that lets registered users opt-in, and then send a basic message saying a new post is available on the site. I filter on snpe_message to remove the default message body and replace it with my own version that does just that.

Private Feed Key Plugin

For contacts who prefer to read their web content in an RSS feed reader, the Private Feed Key plugin is a perfect solution on a private site. It creates per-user private feed URLs for all content on your site, restricting access to registered users only.

Private Feed Key information added to a user's profile in wp-admin

In reality, I suspect I am the only user of our private site actually making use of this feature, but some day I hope one of my geekier users will notice the option and take advantage of it.

Jetpack Plugin

Because Jetpack is generally designed to take advantage of WordPress.com features by (in part) syncing content between a self-hosted site and WordPress.com servers, it can seem like a pretty big departure from the idea of keeping everything contained and private. But with the right settings it can be a great option to add features to a private site without leaking private content. I have the following Jetpack features enabled on my private site:

  • Notifications
  • Site Stats
  • Gravatar Hovercards
  • Protect
  • Extra Sidebar Widgets
  • Widget Visibility
  • Custom CSS
  • Shortcode Embeds
  • Spelling and Grammar
  • Post by Email
  • Beautiful Math (for all that LaTeX we use in talking about parenthood)
  • Custom Content Types
The API, disabled

Of particular note, I have these Jetpack features DISABLED to prevent sharing of private content outside of the site:

  • Manage
  • JSON API
  • Related Posts
  • Subscriptions
  • Enhanced Distribution
  • Photon

Login Lockdown Plugin

Login Lockdown isn't the only security measure I have in place on the server powering this site and is probably the least efficient/secure (I think Jetpack Protect catches a lot of unwanted activity, and my firewall-level blocking catches the rest), but it seemed worth using anyway. It will temporarily prevent visitors from an IP address from attempting to log in to your site if they have so many login failures in a certain period of time. I turned off the locking out of invalid usernames since some of our users had a little trouble remembering theirs, but otherwise plugin has prevented a few bits of unwanted activity and works well.

Disable the JSON REST API

As of WordPress 4.7, a default WordPress install contains an active JSON REST API, a way for other software tools to access information about a site and its content. If access isn't disabled or restricted, someone could use the API to view your private site content. There's a simple Disable REST API plugin that takes care of this for you, or you can add the following code to your theme's functions as recommended by the WordPress documentation:

// Disable the JSON REST API in WordPress Core
add_filter( 'rest_authentication_errors', function( $result ) {
    if ( ! empty( $result ) ) {
        return $result;
    }
    if ( ! is_user_logged_in() ) {
        return new WP_Error( 'rest_not_logged_in', 'You are not currently logged in.', array( 'status' => 401 ) );
    }
    return $result;
});

Conclusions

Having used the private site with the above configuration for while now, a few things stand out:

  • It's not Facebook. Facebook is a consistent part of so many people's online lives and it offers friction-free access to photos and content shared by their "friends" all day long. No matter how clear I thought the instructions were or how straightforward the registration/access process seemed on our site, it introduced a weird new way of accessing private stuff that threw off some of our friends and family and meant a higher bar for them to see our content. I'm sure in some cases that they didn't bother, or never came back after the first visit, and that's fine. For me the value of keeping things on a private site outweighs those downsides, but I know that equation will turn out differently for others.
  • It's not really private. As I mentioned above, I assume that everything connected to the Internet will be made public at some point. There's nothing stopping a user from logging in to our site, copy/pasting the content, and then emailing it out to a bunch of other people. The service that hosts my server could leave a backup tape on a train. A bug in one of the above plugins or a change in how Jetpack works could unintentionally allow access. And so on...user beware.
  • It's not that accessible to the typical site builder. This particular combination of site hosting setup, plugins installations and configurations, theme customizations and other tasks was really straightforward for me, but probably isn't that easy for the average person out there wanting to create a new private website. The WordPress.com option I mentioned at the beginning is a great one, but I still wish there were even more options out there that didn't require handing over your content ownership or agreeing to problematic terms of use.

All in all, I was glad for the experience of creating this site. We still post to it semi-regularly and have interactions through it with people near and far who we don't otherwise get to see often. And yes, we still also use Facebook once in a while to share photos of our life, knowing that they need to essentially be considered out of our control, and we're fine with that.

Are there other tools you can recommend for building a private website? How do you think about protecting your personal content on the web?

Updated March 28 to add a section on disabling WordPress core's JSON REST API, h/t Thomas Kräftner.

Published by

Chris Hardie

Chris Hardie is an Internet tech geek, problem solver, community-builder and amicable cynic.

Leave a Reply

Your email address will not be published. Required fields are marked *