to stand up a writefreely instance with docker


Hello is this thing on

Hi? Hi. You're here. I'm here! I think I'm live?

Let's just get down to brass tacks. Writefreely has a setup guide, and somebody named Karl wrapped it all up into a Dockerfile. I borrowed heavily from both resources to end up here. I'm not putting my configs in a nice repository to share because they're probably terrible and should not be used by anyone, but they seem to be working so I'll talk about them.


The official Dockerfile is intended for theme development, and it does a full build with Go. Karl's Dockerfile extends on the official one, and also does a full build with Go. I don't need a full build with Go; I just need the latest release.

I'm setting up volumes for things I want to be able to back up easily:

FROM alpine:3

WORKDIR /writefreely

VOLUME /data
VOLUME /config
VOLUME /writefreely/keys

I have no idea if this is actually necessary but it was in the official image and it's pretty lightweight, so I kept it.

RUN apk add --no-cache openssl ca-certificates

I'm using ARG with a default version so I can change the version later without changing the Dockerfile. I dump the release directly into my WORKDIR, and that's it. That's the whole file.

ARG version=0.13.2

RUN wget -qO-${version}/writefreely_${version}_linux_amd64.tar.gz \
    | tar -C .. -zvx


I'm using docker-compose, not docker compose, because the other containers on my box use docker-compose and when I tried docker compose something yelled at me. I don't even remember what. Doesn't matter. docker-compose is fine.

Maybe I'll migrate off SQLite someday and need a writefreely-db service. It could happen. You don't know.

version: "3"


Yep, it builds the container directly from the Dockerfile in the same directory. Is that bad? It seems to work fine.

    tty: true
    container_name: writefreely
    restart: always
      context: .

Here's where I can override that ARG in the Dockerfile. I assume this'll only work for patch releases, and if I'm very very lucky, minor releases.

        - version=0.13.2

Those VOLUMEs from before also live in the current directory, so it's easy to wrap the whole thing up and ship it off to my bucket.

      - ./keys:/writefreely/keys
      - ./data:/data
      - ./config:/config

I got pretty into the weeds with ENTRYPOINT and CMD, but I think setting command here is generally fine? I always have the option to override it (which was necessary during setup).

    command: ./writefreely -c /config/config.ini

Because you know why, because Docker still bypasses ufw firewall rules, that's why.

      - ""


Nginx has done a nice job reverse-proxying Docker for me in the past, so I borrowed configs from the official guide almost wholesale. I made two changes:

  1. I don't think there's a good reason not to gzip JS files, so I added text/javascript to the gzip mime-type list, and
  2. I had to change proxy_pass from to Something something docker something, I'm sure this makes sense but I don't care that much.


Karl does a neat thing with a custom ENTRYPOINT that looks for missing things and backs stuff up and all kinds of jazz. It's real nice and too fancy. Way too fancy.

I followed the official setup guide, but I ran everything in the container with docker-compose:

$ sudo docker-compose up --build -d
$ sudo docker-compose exec writefreely-web ./writefreely -c /config/config.ini config start
$ sudo docker-compose exec writefreely-web ./writefreely -c /config/config.ini keys generate

So that's how that happened, and now here we are.

#docker #writefreely #nginx #devops #fediblog