Read-only Public Site

Making your public site read-only will prevent even a compromised site from taking any damage--even if a malicious user does somehow gain access, they can't save any different data to the database.

There are a few ways to do this:

  • Zope Replication Services(ZRS) allow you replicate a read-write backend private server to a read-only public facing site
  • You can also use RelStorage for you zeoserver. Then use the replication facilities provided by some RDMSs to replicate to a read-only zeoserver on the public site.
  • It is also possible to have read-only zeo clients connected to a read-write zeo server.
  • zeoraid might even be an option(never tried it)

One thing to note is that there are some cases where Plone will try to write on read unfortunately. To get around this, I create a before commit event handler in a policy product to abort every transaction when the server is read-only. It's kind of hackish but a necessary evil to prevent a user from getting a nasty ReadOnly database error thrown at them. It would look something like:

from zope.component import adapter
from ZPublisher.interfaces import IPubBeforeCommit
import App.config
import transaction
configuration = App.config.getConfiguration()
readonly = configuration.read_only_database
def abortTransactionOnReadOnly(event):
if readonly:

Rewrite Login URLs

You can also rewrite login urls on the public site to restrict anyone from seeing a login form. Just do normal rewrites at your proxy server.

Urls you'll want to rewrite are:

  • /manage
  • /login
  • /logged_out
  • /require_login
  • /acl_users

This will prevent anyone from seeing a login form and an unauthorized page.

You also might want to disable basic auth on the proxy server.

Keep it Secret, Keep it Safe

It's best if no one knows where your backend, read-write server is located except your content curators. What's more important is that even if someone knows where your site is located, they can't access it without some form of authentication first(in addition to normal plone authentication). There are a few ways to accomplish this:


  • Factored Authentication: Require something like SecureID to protect access to the read-write server
  • Basic Auth: If you're cheap and not hyper sensitive about the security, you could just provide an additional basic auth layer of authentication to prevent any access to the read-write server--just give all content curators the same username:password and then they login again to the Plone site.
  • Make site only accessible via VPN
  • Only provide access to the site on a local network at the workplace


If your read-write server is accessible in anyway(even if behind a factored authentication) you should still try and protect the knowledge of its existence.

  1. Provide an overriding robots.txt to deny all search engines from indexing your read-write site url. This can be done with simple nginx and apache rules.
  2. Make sure your content editors do NOT link to your read-write server. As silly as this sounds, it WILL happen if you don't do anything to prevent it.  You can customize Tiny MCE to filter urls. Basically, customize tiny_mce_init.js in portal_skins/custom adding somethings like:
    var bad_urls = [
    var replace_link = '';
    function filter_links(url, node, on_save){
        for(var i = 0; i < bad_urls.length; i++){
            var bad = bad_urls[i];
            url = url.replace(bad, replace_link);
        return url;
                urlconverter_callback : filter_links

    This will prevent any from being able to link your read-write server.

  3. I also have run scripts periodically that go through all the content of the site looking for bad links. This then checks on people potentially using kupu or putting links into fields that do not have WYSIWYG editors.


This might be obvious, but you need to make you have some sort of monitoring in place to track rejected logins to your backend. This will depend on what you've used to secure your backend.