Rob's Writefreely Dev Log

A place to share my journey helping build writefreely and related projects


Hoping that this fixes the issue with hubzilla URLs being arrays

it did not

This instance will be used for possibly breaking test changes.

As such I will be moving my development blog to Please feel free to unfollow this account and follow the other instead.

This is a quick guide on hardening sshd on a server.

I like 'vim' as my editor, but you can use vi or nano. If you don't know what I'm talking about use 'nano'

Open the sshd config in your editor of choice: vim /etc/ssh/sshd_config. We will mostly be removing the comment character # from the beginning of the line, and then making any change to the value.

Disallow Root Login

Find the line #PermitRootLogin no and change it to:

PermitRootLogin no

Disallow Password Logins

Find the line #PasswordAuthentication yes and change it to:

PasswordAuthentication no

Resrtict Users

Find the line #AllowUsers, or create it if it doesn't exist, and change it to:

AllowUsers your-user-name

Change Port

If you chose to use a different port, find the line #Port 22 and change it to:

Port number-you-want

Then after you save the file, :wq in vim. Restart sshd, sudo systemctl sshd restart.

This guide will walk you through the process of installing WriteFreely on Ubuntu 19.04 Disco Dingo.

We will run WriteFreely behind nginx , so we can run other applications on the same server.

In this guide we will setup the application for multiple user's and with registrations open. You can adjust to your use case, details will be provided.

I will give instructions assuming your are logged into your server are root for the duration of this guide. If you prefer to login with the user created in the guide you will need to use sudo. i.e. sudo ufw allow ssh

Server Set Up

Start by provisioning a new Ubuntu 19.04 VPS, or get an image and install Ubuntu on an old computer.

Without a VPS you will likely need to find another method of obtaining and using a static IP address, which is outside the scope of this article.

I like to use Vultr *affiliate link, you get $50 free credit and I get $25.

Basic Security Hardening

I'm going to cheat here and just give an overview and some links.

There are a few basic things you should have in place to protect your new server from curious third parties.

Create Another User

This will be the user account you use when administering the server, it should have sudo privileges. guide

Restrict SSH

Before you make any changes make sure you have generated an SSH key on your local machine. Then copy the ID up to the server. ssh-copy-id username@server-ip, assuming you created the standard ./ssh/

Then disallow root login over SSH, as well as password based logins.

Some people prefer to change the default port, which doesn't stop potential intrusions but does reduce the logging and attempts.

My own guide here.


A basic firewall goes a long way. Using UFW makes this easy.

Allow ssh, so we can come back and don't lose our connection when we restart the SSH daemon. ufw allow ssh

Then enable it with ufw enable, you can see the status with ufw status.


Fail2Ban helps filter out and ban failed login attempts, as well as provide some insights as to the current volume and origin of attempts. guide


In this guide we will set up the open source mysql implementation, MariaDB.

Follow the set up here and remember to store your secure admin password somewhere safe. *The tutorial is for 18.04 but should work the same.


Follow the guide here *Again for 18.04 but nothing has changed here.

Install and Configure WriteFreely

Now we will go over the installation and configuration of the WriteFreely application itself. This includes setting up our database and NGINX configuration.


Download and install the latest version of WriteFreely from here.

Then follow the production guide.

During writefreely --config you need to chose the following, most are default: * Server setup: * Production, behind reverse proxy * Local port: 8080 * Database setup: * MySQL * Username: pick a mysql username * Password: pick a mysql password * Host: localhost * Port: 3360 * App Setup: * Multi-user instance * Instance name: chose an instance name * Public URL: enter a public domain you own * Registration: you pick * Max blogs per user: you pick * Federation: enabled * Federation usage stats privacy: public * Metadata privacy: public

You can just copy the NGINX config from that guide and use it to replace the contents of your /etc/nginx/sites-available/default. Make sure to edit the parts in bold.

Do the same for the systemd service making necessary changes.

Let's Encrypt

Before starting this, make sure to update your domain's DNS settings to point at the new server, unfortunately outside the scope of this guide.

Now add the certbot ppa:

$ apt-add-repository ppa:/certbot/certbot

Press enter to confirm when prompted. Then update the cache and install cerbot with it's dependencies:

$ apt update
$ apt install certbot python-certbot-nginx

Then have certbot setup and provision some certificates for you. Follow the prompts provided.

$ certbot --nginx

That's it for certificates. The email entered during this step will be notified when expiry is getting close. It should take care of that automatically with a cron job though, to test if it's working run certbot renew --dry-run.

First Run

On the first run, the user you sign up with becomes the admin. Then you can adjust some of the settings from within the admin panel.



Coming soon. I promise, as soon as I figure it out.

Storage Off-Site

I use a home server that is not exposed to the internet to sync backups from my cloud VPS. It's just a cron job and a simple script that runs rsync. The home server has it's own ssh key for authentication.

Say what?

Yes, I'm currently working on support for not only instances other that but multiple authenticated users at one time.

This would mean you can stay logged in on, your personal instance and any other number. A default host and user will be supported in config, as well as a default user for each host. You can also pass a host and or user during command execution to determine which account and instance to operate on.

This is all for now, this message was written using the WIP wf binary.

I started strong and forgot my password for this development instance.

Turns out it's quite simple, if your the admin or someone with access to the server.

There is a command line flag for resetting a user password. --reset-pass

The full command would be writefreely -c <path to config file> --reset-pass <user to reset>. You are then prompted for the new password, the password is not confirmed at this time so type carefully or copy paste.

Happy writing.

As this is a development instance, intended to test features and fixes, I am going to run it as a single user.

To do the same you need to edit you config.ini file:

single_user = true

I intend to host another instance under one of my domains for myself and family to use. Stay tuned.