Install WriteFreely with Apache and MySQL

Hi all,

After stumbling across WriteFreely quite recently, I was eager to give it a go. I spun up a VM and went about installing it, using Apache as the web server (I’m more familiar with this than Nginx) and MySQL as the db backend (was looking to integrate WF into an existing web server with MySQL already in use). Here’s my guide on getting it setup, along with obtaining an SSL certificate via Let’s Encrypt. I used Ubuntu Server 18.04 as my OS. This guide is for a fresh install, so adapt it if you already have a server. I use ‘’ as a placeholder for your own URL. So long as you’re DNS records are updated, you can use a subdomain such as ‘’.

Update & upgrade system
sudo apt update && sudo apt dist-upgrade

Install Apache
sudo apt install apache2

Start Apache
sudo systemctl start apache2

Install MySQL
sudo apt install mysql-server

Configure MySQL
Decide yourself on the how you want it setup
sudo mysql_secure_installation

Enable Apache modules
These modules allow us to use Apache as a reverse proxy
sudo a2enmod proxy
sudo a2enmod proxy_http

Restart Apache
sudo systemctl restart apache2

Create MySQL Database
Can leave password blank when prompted
sudo mysql -u root -p

When at the mysql> prompt:
CREATE USER 'writefreely'@'localhost' IDENTIFIED BY 'YouPasswordHere';
CREATE DATABASE IF NOT EXISTS writefreely CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
GRANT ALL PRIVILEGES on writefreely.* to 'writefreely'@'localhost';

Create and change to directories
sudo mkdir /var/www/
sudo mkdir /var/www/
cd /var/www/

Download WriteFreely
Get the link for the latest Linux version from HERE. If you’re using SSH from a device you have internet access to, an easy way to do this is to right-click the link for the Linux version, which is writefreely_0.9.1_linux_amd64.tar.gz at time of typing, and select Copy Link Location (or your web browser equivalent). Then, simply paste the link into the command below.
sudo wget LINK

Uncompress downloaded file
Adapt for version you downloaded
sudo tar -xvzf writefreely_0.9.1_linux_amd64.tar.gz

Remove file
No need for it after we have uncompressed it
sudo rm writefreely_0.9.1_linux_amd64.tar.gz

Configure WriteFreely

  • Choose Production, behind reverse proxy
  • Keep local port as 8080
  • Choose MySQL enter the details for the MySQL database (as per my example, writefreely as both username and database name, then the password you chose)
  • Choose if you want a Single user blog or Multi-user instance (doesn’t matter either way)
  • Enter admin details (if Single user blog was chosen above)
  • Use the URL you want to use for WriteFreely as the Public URL
  • Make whichever choice you want for Federation, Federation usage stats and Instance metadata privacy

sudo ./writefreely --config

Import schema for multi-user setup and create admin user - only if you chose Multi user instance above
sudo ./writefreely --init-db
sudo ./writefreely --create-admin [username]:[password]

Generate data encryption keys
sudo ./writefreely --gen-keys

Create Virtual Host for Apache
sudo nano /etc/apache2/sites-available/writefreely.conf

<VirtualHost *:80>

    ProxyPreserveHost On

    ProxyPass /
    ProxyPassReverse /

Enable Virtual Host
sudo a2ensite writefreely.conf

Disable existing default Virtual Host
sudo a2dissite 000-default.conf

Reload Apache
sudo systemctl reload apache2

Create systemd service
sudo nano /etc/systemd/system/writefreely.service

Description=Write Freely Instance



Enable service
This will then start the service every time the system boots
sudo systemctl enable writefreely.service

Start service
sudo systemctl start writefreely.service

Install certbot - for Let’s Encrypt SSL certificate
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot
sudo apt-get install certbot python-certbot-apache

Run certbot
Select the URL you want to add the SSL certificate for, then choose whichever options after.
sudo certbot --apache

That should be you. Please let me know if I’ve made any mistakes, or if there are easier ways to do what I’ve done. I can’t say I’m an expert with Linux, so would greatly appreciate feedback.


This is awesome. Thanks for writing it up and sharing, @kingprawn22!

1 Like

Hey there,
I’m not an advanced user and I host already few of my services. I have a problem to make it work together. So as for now different pages had a simple public.html file in subfolders of /var/www/ (I work on linux) and I’ve been just adapting apache2 conf file and sites-available sites’ conf files by addition of

Alias /abab “/var/www/abab/”
<Directory /var/www/abab/>
Require all granted
Options FollowSymlinks MultiViews
AllowOverride All

SetEnv HOME /var/www/abab
SetEnv HTTP_HOME /var/www/abab

Something like this. Here the conf file looks somehow different and my trials didn’t work. How to set it up, so that I could have my blog on

Right now it looks like:

<VirtualHost *:80>
ServerAdmin …
ServerName …
ServerAlias …
Alias /wf “/var/www/writefreely/”
DocumentRoot /var/www/writefreely
ProxyPreserveHost On
ProxyPass / ht tp://
ProxyPassReverse / ht tp://
<Directory /var/www/writefreely>
SetEnv HOME /var/www/writefreely
SetEnv HTTP_HOME /var/www/writefreely
Satisfy Any

< /VirtualHost>

There’s no errors while reloading apache, but the site doesn’t show up at localhost/wf and that’s the goal.

Did you create and start the writefreely service?


hmm, what do the writefreely logs say? journalctl -f -u writefreely might need sudo

Beggining of it. I have a conflict with nextcloud… hmm how to fix it?? Also it didn’t get a user for some reason.

– Logs begin at Thu 2018-08-09 16:51:50 CEST. –
lis 27 15:07:14 …@… writefreely[27753]: 2019/11/27 15:07:14 “GET /writefreely” 401 33.20602ms “Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0”
lis 27 15:07:14 …@… writefreely[27753]: 2019/11/27 15:07:14 “GET /login?to=/writefreely” 200 549.789µs “Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0”
lis 27 15:07:23 …@… writefreely[27753]: 2019/11/27 15:07:23 Handler: Required a user, but DIDN’T get one. Sending not logged in.
lis 27 15:07:23 …@… writefreely[27753]: 2019/11/27 15:07:23 “GET /nextcloud” 401 266.374µs “Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0”
lis 27 15:07:23 …@… writefreely[27753]: 2019/11/27 15:07:23 “GET /login?to=/nextcloud” 200 533.446µs “Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0”
lis 27 15:07:39 …@… writefreely[27753]: 2019/11/27 15:07:39 Login: Attempting login for ‘myuser
lis 27 15:07:39 …@… writefreely[27753]: 2019/11/27 15:07:39 Login: Redirecting to /nextcloud

I’ve changed the conf file to look like this:

<VirtualHost *:80>
ServerAdmin …@…
ServerName …
ServerAlias …
ProxyPreserveHost On
ProxyPass / ht tp://
ProxyPassReverse / ht tp://
</ VirtualHost>

and the log went really nice except that the last line is:

Serving on ht tp://localhost:8080

and not:

Serving on ht tp://localhost/wf:8080

ok now I’ve changed rather the config.ini file in the writefreely to be:

bind = localhost/wf (instead of just localhost)

and had few errors (ERROR: 2019/11/28 19:37:20 app.go:463: Unable to start: listen tcp: lookup localhost/wf: no such host), but it already wanted to host at localhost/wf so not that bad, maybe here is something to change?
The line host look like this since the beggining:

host = http://localhost/wf:8080

Haven’t been able to dig into this yet, but just wanted to mention that WF doesn’t officially support installation on a path like /abab. Recommended way to install would be to do it on, instead.

1 Like

Ok, it worked. I now need to work a bit with ports, so it could run on wf.localhost instead of wf.localhost:8080 and for some reason I cannot make a post now, maybe some ownership issues, but generally it runs…
Thank you

1 Like

I came across this post when trying to set up my own Apache reverse proxy. I had already setup a very basic proxy which let me access the site and write new articles, but federation didn’t work. The related part in the sample Nginx configuration is this one:

       location ~ ^/.well-known/(webfinger|nodeinfo|host-meta) {
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $remote_addr;
       proxy_redirect off;

I ended up adding this line to my Apache virtual host:

ProxyPassMatch ^/.well-known/(webfinger|nodeinfo|host-meta) !

I can now connect from my Mastodon account, and new posts on WriteFreely show up there.

I thought I might add this in case somebody else comes across this post trying to solve the same issue.

1 Like

Thanks for providing this, the writefreely.conf file would not allow apache to continue to serve my existing web site as well as serve other go applications.

I am trying to figure out the best way to do this I am thinking a subdomain. But I am not sure how to implement the ssl. Am I correct in saying if you have apache handing the ssl there is no need to encrypt the data on the application side.

currently my server redirects all port 80 trafic to ssl using this in my 000.default.conf
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

My 000-default-le-ssl.conf uses redirects to talk to the endpoints of my go applications

# This file is working with userlogin.go feb 21-2020 # ServerName ServerAdmin webmaster@localhost
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

SSLEngine on
SSLProxyEngine on


<Directory />
Options FollowSymLinks
AllowOverride None

<Directory  /var/www/html>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all

 RewriteEngine on

 RewriteRule ^(lotto)$ http://localhost:8000/$1 [P,L]	
 RewriteRule ^(internal)$ http://localhost:8000/$1 [P,L]
 RewriteRule ^(login)$ http://localhost:8000/$1 [P,L]
 RewriteRule ^(logout)$ http://localhost:8000/$1 [P,L]
 RewriteRule ^(save)$ http://localhost:8000/$1 [P,L]
 RewriteRule ^(results)$ http://localhost:8000/$1 [P,L]

SSLCertificateFile /etc/letsencrypt/live/
SSLCertificateKeyFile /etc/letsencrypt/live/
Include /etc/letsencrypt/options-ssl-apache.conf

Worth mentioning that in your SSL Apache conf file you need to have

SSLProxyEngine on
SSLProxyVerify none

or things don’t work properly too.