Pleroma is an open source social network platform that is a part of the Fediverse. In this write-up, I will be describing my experience with installing the OTP release on a Linux VM in Google Cloud by following the official documentation.

For someone who works with Kubernetes clusters daily and deploys to them using Helm, the idea of manually configuring a VM to run my application is an adorable flashback to a simpler time. It brings me back to my days as a student systems administrator at Oregon State or the very early days wherein I would run Unreal Tournament servers from my home Linux computer. Are you feeling the nostalgia?


A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and x86_64, aarch64 or armv7l CPU, you have root access to. If you are not sure if it’s compatible see Detecting flavour section below
A (sub)domain pointed to the machine

I’m going to handwave over this a bit, Google Cloud and my DNS provider Cloudflare are going to have much better docs on it than I am. Aside from a little annoyance with setting up Google Cloud to play nicely with my Legacy GSuite Account, getting a e2-small (2 vCPUs, 2 GB memory) with a static IP setup and an A Record from CloudFlare was easy enough.

Installing the required packages

A pretty uneventful set of packages. The docs describe each one’s purpose. Went ahead and installed them on the VM over SSH.

Configuring PostgreSQL

The developer docs provide some useful tuning config for a small 2GB/2CPU instance like I’ve provisioned so I’m popping the config values below into /etc/postgresql/11/main/postgresql.conf. Beware of just pasting those values in, they already exist in the config! To save myself future confusion, I uncommented/updated the values provided in the config file by the system package. The values check out with what I’ve seen previously coming out of PGTune in my professional life.

shared_buffers = 512MB
effective_cache_size = 1536MB
maintenance_work_mem = 128MB
work_mem = 26214kB
max_worker_processes = 2
max_parallel_workers_per_gather = 1
max_parallel_workers = 2

Installing Pleroma

Next up, making a user for the service, downloading the release, making a bunch of directories, etc. The developer includes what is essentially a shell script in the docs, so I copied the whole thing and put it in a shell script with a few tweaks:

  • Took the arch detection code from the top of the doc and injected it as below. This makes the script auto-detect the arch, which afaik is the only input needed on this script.
arch="$(uname -m)";if [ "$arch" = "x86_64" ];then arch="amd64";elif [ "$arch" = "armv7l" ];then arch="arm";elif [ "$arch" = "aarch64" ];then arch="arm64";else echo "Unsupported arch: $arch">&2;fi;if getconf GNU_LIBC_VERSION>/dev/null;then libc_postfix="";elif [ "$(ldd 2>&1|head -c 9)" = "musl libc" ];then libc_postfix="-musl";elif [ "$(find /lib/libc.musl*|wc -l)" ];then libc_postfix="-musl";else echo "Unsupported libc">&2;fi;echo "$arch$libc_postfix"
export FLAVOUR="${arch}${libc_postfix}"

Script ran with no issues. The little auto-configuration wizard that Pleroma includes is pretty easy to breeze through. Once it was up, standard Let’s Encrypt SSL setup. I’ll probably transition away from it and use the CloudFlare provided Origin certs eventually, but this let me turn on Strict SSL faster and with minimal hassle so It Works For Now(tm). Pleroma provided an Nginx config that I only needed to sed the example.tld out of and copy over, and then it’s off to the races with a functioning instance! Don’t forget to setup Let’s Encrypt auto-renewal, folks.


Overall, the process wasn’t too bad, once I quieted the voice in my head that tells me to run everything in Kubernetes and decided I was fine with running directly on a VM instead. Happy microblogging!

Despite working for Facebook a few years ago, I’m not a huge fan of the platform. I think that attempting to cram every human being on the planet into one massive social network without any concept of community enforcement is counterproductive and antithetical to how humans are capable of socializing. We evolved to interact with small bands of hunter-gatherers, not thousands of individuals via highly abstract proxies for interaction such as Likes and Hearts. This has been written about in much more detail than I can do justice by many people much smarter than me so I won’t attempt my own “hot take” on it. If you are curious about the concept, look into Dunbar’s Number.

Given that preface, I hope that you find it easier to understand why I’m interested in finding alternative social networks. I have no distaste for idea of a social network. To the contrary, I find the general concept of individuals being able to easily share information with each other as a group is often beneficial for everyone involved and has the potential to strengthen our collective powers. Social networking has allowed many people to band together and organize political and activist projects that have done an incredible amount of good in the world. Our feeds have allowed many marginalized and ignored groups to have a voice where the television and newspapers reporters of the past wouldn’t have seen a story.

Does a network with that sort of power exist today without being beholden to a mega-corporation? What sort of founding principles would guide a network in a way that it could resist that sort of control and influence while still providing power to the people? I want to find out, so I’m going to attempt setting up as many social networks as I can find and then writing them up here. Before I start out on that quest, I would like to outline the criteria that I’ll be looking for:

  • Open source: The code for the network must be available freely to everyone under a licence that will not allow it to be hijacked by a massive corporation. This ensures that anyone can run the network and that no one will be allowed to become a gatekeeper. Provided that there are well documented APIs available, I may consider it acceptable if there are closed-source mobile clients as long as other clients are permitted by the licencing.
  • Federated: There must be no central control to the network. Each node should be able to freely associate with any other, or choose to completely dissociate with another node. This reflects the nature of human society and allows people to form webs digital webs of trust.
  • Community-focused: Nodes in the social network must have good community management features included that allow operators of a node to moderate users and build effective communities where people are not afraid to express themselves.
  • User friendly: User interfaces are a critical part of any digital experience and a social network is no different. People have to be able to use the thing in an easy to understand way, even if that means sacrificing VIM keybindings.

I’m interested in looking into Diaspora, Mastodon, Friendica, and PixelFed. I’ll prefer running them in Kubernetes when at all possible and will consider making upstream contributions to make that easier for others. As I experiment with these platforms, I’ll either continue to update this post or make new follow up posts. Thank you for reading!

My previous “blog” was “written” with Hugo and hosted on Netlify. I use quotes because for the last two years it had no content at all so it wasn’t much of anything. Today I was chatting at work with some folks about what blog platforms we use and I wanted to not feel like such a poser.

That preface out of the way, I’ve decided that a new year means a new blog and I’m resolving to write weekly about my various adventures and thoughts revolving around technology here. Hopefully 2020 is a better year in oh so many ways. “What is this new blog written in?” you ask. It’s Hexo and it is running on Zeit Now.

Why did I chose those two? Despite my firey hate of all things JavaScript, it is a useful language to learn, the community around Hexo seems much more vibrant, and it’s stupidly easy to use. As for my decision to use Zeit, it seems like if I want to jump into any squirrely experiments with different cloud platforms and serverless functions, Zeit is much more flexible than Netlify while still retaining the simple Github-based workflow that I like.

Given how much easier it should be to maintain and update this blog, I’m hoping it will be easy to keep that resolution to write here biweekly. 🤞

How I set this up on OSX

  1. Delete old empty blog commit

    # nuke everything, boring git stuff
    git rm -rf *
    git commit -m 'Dump netlify and hugo'
    git push origin master
  2. Install NodeJS and hexo

    brew install nodejs # could also download the pkg or YOLO curl | bash
    npm install hexo -g
  3. Use hexo init to make a new blog from the default template

    Since I already had a git repo checked out, I had to use hexo init in a subdirectory and move it out.

    hexo init blog
    mv blog/* .
  4. Fiddle with _config.yml commit

    Yet another YAML file in my life. Browsed through it and fiddled with settings like title, url, etc.

  5. Make the beginnings of this blog post commit

    Created a new file source/_posts/New-Year-New-Blog.md by calling hexo new 'New Year New Blog'. Filled it out with some pretty standard Markdown content.

  6. Add a theme and fiddle with it’s settings commit

    I was originally going to use git submodule to checkout my fork of the theme I found but then I remembered that submodules are terrible so I used git rebase -i to pave over that chapter of history, replaced it with a literal copy of my local checkout of my fork (minus the .git folder) and force pushed git push origin master -f over the evidence. 🔥📁🔥 I’ll just pull down from upstream on my fork and copy over the files whenever I want to update or make changes.

    In Hugo, themes can also have settings. So I fiddled around with those a bit. 🤷‍♂️ I just have to remember to copy the _config.yml hacking I did back over to my fork of the theme.

  7. Make this blog post :inceptiontop: commit

    Checked out what it will look like locally with hexo server.

  8. Login to Zeit create a new project

    I created a new project, filled it out with the details for my blog and linked it to my Github repo. I restricted the permissions to the small set of static sites that I deploy and not include the hundreds of work forks. It’s pretty easy to update them again later, if you search for a repo but Zeit can’t find the repo, Zeit offers a link to the app config on Github.

    Once the repo was added, Zeit immediately began build it (I think it uses npm actions in package.json) and then deployed it to a temporary domain.

  9. Setup Zeit domain

    I didn’t want to have to deal with NameCheap and CloudFlare for this silly blog, so I ported DNS management over to Zeit on NameCheap. For some reason the bulk edit didn’t like the single character subdomains on Zeit (for example, a.zeit-world.org) but the “Manage” screen was fine with it. 🤷‍♂️ Sounds like a fun bug for someone that isn’t me to fix. DNS migrated super-quick and easy.

    NameCheap DNS Setup Screenshot

    I decided I wanted to add a screenshot, which required adding hexo-asset-link via npm i --save hexo-asset-link.

That’s about it. Hopefully you’ve learned something from this overly verbose guide. 😅 Hello to all the crawlers and bots out there!