Blogging in Golang with WriteFreely and Caddy

Blogging in Golang with WriteFreely and Caddy

I realize it is ironic to write a Medium post about setting up a personal blogging platform, but more and more people are looking at doing that these days — people who are concerned about privacy, or who want to have more control over their writing, or who want to be in charge of their data.

I’ve been looking for blogging software written in Golang, and I haven’t been very successful. Projects like Hugo are very popular as static site generators, but I was also looking for an interactive web editor. I finally stumbled on WriteFreely, a minimalistic yet elegant blog engine written in Go. I have also wanted to experiment with Caddy for a long time, so in this post I will show how to use it as a reverse proxy in front of a WriteFreely blog site.

My setup is based on an Ubuntu 20.04 instance deployed in the Google Cloud Platform.

Install go 1.17


# apt remove — autoremove golang
# wget
# rm -rf /usr/local/go
# tar -C /usr/local -xzf go1.17.5.linux-amd64.tar.gz
# sh -c ‘echo “export PATH=$PATH:/usr/local/go/bin” >> /etc/profile’

# apt update# apt remove — autoremove golang# wget https://go.dev/dl/go1.17.5.linux-amd64.tar.gz # rm -rf /usr/local/go# tar -C /usr/local -xzf go1.17.5.linux-amd64.tar.gz# sh -c ‘echo “export PATH=$PATH:/usr/local/go/bin” >> /etc/profile’

Install MySQL server v8.0.x

# apt install mysql-server
# mysql_secure_installation

Install Write Freely in /var/www/myblog.com


# cd /var/www
# cp ~/
# tar xvfz
# mv writefreely myblog.com
# rm

# wget https://github.com/writefreely/writefreely/releases/download/v0.13.1/writefreely_0.13.1_linux_amd64.tar.gz # cd /var/www# cp ~/ writefreely_0.13.1_linux_amd64.tar.gz # tar xvfz writefreely_0.13.1_linux_amd64.tar.gz # mv writefreely myblog.com# rm writefreely_0.13.1_linux_amd64.tar.gz

Create WriteFreely database and user

# mysql -uroot -p

Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.27–0ubuntu0.20.04.1 (Ubuntu)

mysql> CREATE DATABASE writefreely CHARACTER SET latin1 COLLATE latin1_swedish_ci;
Query OK, 1 row affected (0.01 sec)

mysql> create user ‘wfdbuser’@’localhost’ identified with mysql_native_password by ‘somestrongpassword’;
Query OK, 0 rows affected (0.01 sec)

mysql> grant all on writefreely.* to ‘wfdbuser’@’localhost’;
Query OK, 0 rows affected (0.00 sec)

Install and configure WriteFreely

# cd /var/www/myblog.com
# ./writefreely config start
# ./writefreely keys generate

The writefreely config start command will ask a series of questions. I chose to configure a single-user blog in production mode, behind a reverse proxy. One thing to note is that you need to set the host value in the [app] section to the actual URL of your blog — something like https://www.myblog.com.

Create systemd service for WriteFreely

# vi /etc/systemd/system/writefreely.service
# cat /etc/systemd/system/writefreely.service
[Unit]
Description=WriteFreely Blog Engine
After=syslog.target network.target
# If MySQL is running on the same machine, uncomment the following
# line to use it, instead.
After=syslog.target network.target mysql.service
[Service]
Type=simple
StandardOutput=syslog
StandardError=syslog
WorkingDirectory=/var/www/myblog.com
ExecStart=/var/www/myblog.com/writefreely
Restart=always
[Install]
WantedBy=multi-user.target

Start up WriteFreely service and enable it for boot time startup:

# systemctl start writefreely
# systemctl enable writefreely

At this point the writefreely process is running and listening on localhost:8080.

Set up reverse proxying with Caddy

Set up DNS

Point myblog.com, www.myblog.com and media.myblog.com to the external IP of the GCP instance.

Install Caddy via deb package


# dpkg -i caddy_2.4.6_linux_amd64.deb
# which caddy
/usr/bin/caddy
# caddy version
v2.4.6 h1:HGkGICFGvyrodcqOOclHKfvJC0qTU7vny/7FhYp9hNw=

# wget https://github.com/caddyserver/caddy/releases/download/v2.4.6/caddy_2.4.6_linux_amd64.deb # dpkg -i caddy_2.4.6_linux_amd64.deb# which caddy/usr/bin/caddy# caddy versionv2.4.6 h1:HGkGICFGvyrodcqOOclHKfvJC0qTU7vny/7FhYp9hNw=

Create Caddyfile config file

The magic of Caddy can be seen in the simplicity of its config file. By simply declaring the virtual hosts we need Caddy to handle, we make sure that TLS is also set up “automagically” by Caddy via Let’s Encrypt.

# mkdir /var/www/media.myblog.com
# mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.orig
# vi /etc/caddy/Caddyfile
# cat /etc/caddy/Caddyfile


redir
}

myblog.com {redir https://www.myblog.com{uri}

www.myblog.com {
reverse_proxy 127.0.0.1:8080
}

media.myblog.com {
root * /var/www/media.myblog.com
file_server
}

The Caddy deb package installation creates a systemd service for Caddy, so we just need to start it up via systemctl:

# systemctl start caddy

# ps -def|grep caddy
caddy 2139 1 2 01:35 ? 00:00:00 /usr/bin/caddy run — environ — config /etc/caddy/Caddyfile

Note that we created a special directory /var/www/media.myblog.com and a new virtual host for Caddy to handle media.myblog.com . This is because the open source version of WriteFreely doesn’t support image uploads, so for images we need to scp them manually to the server and refer to their URLs in the markdown representing the blog post.

WriteFreely has a decent writer guide for writing blog posts. It could be a bit better, but basically you can use the full features of Markdown, including HTML snippets when needed — for example for an embedded YouTube video.

Overall, I’ve found the experience of writing posts with WriteFreely to be a very pleasant one. The experience of running Caddy has been amazing — what a beautiful piece of software. Kudos to the two Matts, Matt Baer for creating WriteFreely and Matt Holt for creating Caddy!