Lemmy
Introduction
Like many other people, I was an avid reader of reddit because it’s vibrant and eclectic communities, world news, and technology discussions. I started using Reddit in its early days, when many users migrated from Digg after a failed redesign. Compared to Digg, Reddit offered richer and deeper content. The memes were funnier, and the discussions more intellectual.
However nothing can last forever, and we’ve seen what’s now commonly referred to as the “enshittenification” of reddit. This term describes how a digital platform’s user experience progressively worsens as it prioritizes monetization and profit over user satisfaction and service quality. This has led to privacy issues, increased advertising, and even propaganda on the platform.
So what alternatives are there?
Open Source and Decentralized Alternatives
Many open source sites aim to replace not just Reddit, but all forms of centralized and proprietary social media. These platforms often use unique protocols to enable decentralized architecture, allowing users to run the software on their own servers. This helps avoid the issues that lead to enshittification. Some of these protocols include Nostr, Matrix, Scuttlebutt, and ActivityPub.
Among these alternatives, one stands out as being closest to the Reddit experience: Lemmy. Designed specifically as a Reddit alternative, Lemmy uses the ActivityPub protocol and is written in Rust. According to The Federation, Lemmy is the second most popular decentralized social media project, after Mastodon. This makes it an ideal choice for those looking to take control of their digital social life.
How to Self Host Lemmy
Note: this is simply how I chose to deploy the software, but there are many ways to achieve this with various tradeoffs.
I use Ansible and the lemmy-ansible
projects to configure and deploy Lemmy on my server. lemmy-ansible
is
a good choice because this handles a lot of the tedious work of configuration
of many components of the system very easily via templates. This way, as
someone who is just trying to run the software without headaches, you only
have to deal with the minimum configuration variables and commands necessary
to stand-up a fully working Lemmy deployment. There are many other tools like
Ansible that are good tools to use, but I use it here because of lemmy-ansible
,
which is a particularly good choice it’s a project maintained by the Lemmy
developers themselves.
Get Started
To get started, clone the lemmy-ansbile
git repo on your personal machine (i.e. not your homelab server) and cd
into the repo you’ve just cloned. Start reading the README
install section commands to get a peek at what we’ll need to do. I’ve
essentially copied the README
installation instructions
to this post so that I can enrich it with more details to make the process easier.
First, checkout the latest official release of Lemmy by running:
git checkout $(git describe --tags)
Then you’ll create the directory for your configuration,
mkdir -p inventory/host_vars/<your-domain>
For me that’s:
mkdir -p inventory/host_vars/lemmy.vegan.dev
Config.hjson
This is the configuration for the Lemmy backend. Copy the sample configuration file:
cp examples/config.hjson inventory/host_vars/<your-domain>/config.hjson
For me that’s:
cp examples/config.hjson inventory/host_vars/lemmy.vegan.dev/config.hjson
After you copy over the examples/config.hjson
, edit it as you wish. I’m sharing
my filled out version here below so you can get a feel of what a finalized config
will look like.
Click to expand config.hjon
{
# for more info about the config, check out the documentation
# https://join-lemmy.org/docs/en/administration/configuration.html
database: {
host: postgres
password: "{{ postgres_password }}"
}
hostname: "{{ domain }}"
pictrs: {
url: "http://pictrs:8080/"
api_key: "{{ postgres_password }}"
}
email: {
smtp_server: "postfix:25"
smtp_from_address: "noreply@{{ domain }}"
tls_type: "none"
}
setup: {
# Username for the admin user
admin_username: "<my-secret-admin-username>"
# Password for the admin user. It must be at least 10 characters.
admin_password: "<my-secret-admin-password>"
# Name of the site (can be changed later)
site_name: "Wavy"
# Email for the admin user (optional, can be omitted and set later through the website)
admin_email: "<my-secret-admin-email>"
}
}
Inventory Hosts
Inventory hosts defines the hosts and groups of hosts upon which commands, modules, and tasks in the Ansible playbook operate.
Copy the sample inventory hosts file:
cp examples/hosts inventory/hosts
Click to see my inventory hosts file
[lemmy]
# to get started, copy this file to `inventory` and adjust the values below.
# - `myuser@example.com`: replace with the destination you use to connect to your server via ssh
# - `ansible_user=root`: replace `root` with your the username you use to connect to your ssh server
# - `domain=example.com`: replace `example.com` with your lemmy domain
# - `letsencrypt_contact_email=your@email.com` replace `your@email.com` with your email address,
# to get notifications if your ssl cert expires
# - `lemmy_base_dir=/srv/lemmy`: the location on the server where lemmy can be installed, can be any folder
# if you are upgrading from a previous version, set this to `/lemmy`
# - `lemmy_version`: <Optional> The back end version.
# - `lemmy_ui_version`: <Optional> overrides the front end version.
# - `pictrs_safety`: <Optional> If true, a docker container for pictrs-safety will be deployed and pict-rs will be configured to validate images through it. You will also need to set up a fedi-safety worker to validate the images.
tom@homelab-server ansible_user=tom domain=lemmy.vegan.dev letsencrypt_contact_email=<my-secret-email> lemmy_base_dir=/srv/lemmy pictrs_safety=false
[all:vars]
ansible_connection=ssh
lemmy_base_dir=/lemmy
Postgres
For the postgres configuration, start by copying the example file:
cp examples/customPostgresql.conf inventory/host_vars/<your-domain>/customPostgresql.conf
For me that’s:
cp examples/customPostgresql.conf inventory/host_vars/lemmy.vegan.dev/customPostgresql.conf
You can then use the PGTune Tool to get the best values for your system if you wish.
Ansible Inventory Vars
There isn’t much to actually customize here, as much of the values are templated by Ansible.
Start by copying the sample vars.yml
file:
cp examples/vars.yml inventory/host_vars/<your-domain>/vars.yml
For me that’s:
cp examples/vars.yml inventory/host_vars/lemmy.vegan.dev/vars.yml
Despite there not being much customization required here, here is my working example for completeness:
Click to see Ansible inventory vars
postgres_password: "{{ lookup('password', 'inventory/host_vars/{{ domain }}/passwords/postgres.psk chars=ascii_letters,digits') }}" # noqa yaml[line-length]:w
# Next two only relevant if pictrs_safety == True
pictrs_safety_worker_auth: "{{ lookup('password', 'inventory/host_vars/{{ domain }}/passwords/pictrs_safety_worker_auth.psk chars=ascii_letters,digits length=15') }}" # noqa yaml[line-length]
pictrs_safety_secret: "{{ lookup('password', 'inventory/host_vars/{{ domain }}/passwords/pictrs_safety_secret.psk chars=ascii_letters,digits length=80') }}" # noqa yaml[line-length]
# You can set any pict-rs environmental variables here. They will populate the templates/docker-compose.yml file.
# https://git.asonix.dog/asonix/pict-rs
pictrs_env_vars:
- PICTRS__SERVER__API_KEY: "{{ postgres_password }}"
- PICTRS__MEDIA__ANIMATION__MAX_WIDTH: 256
- PICTRS__MEDIA__ANIMATION__MAX_HEIGHT: 256
- PICTRS__MEDIA__ANIMATION__MAX_AREA: 65536
- PICTRS__MEDIA__ANIMATION__MAX_FRAME_COUNT: 400
- PICTRS__MEDIA__VIDEO__ENABLE: "True"
- PICTRS__MEDIA__VIDEO__MAX_FILE_SIZE: 20
- PICTRS_OPENTELEMETRY_URL: http://otel:4137
- RUST_LOG: info
- RUST_BACKTRACE: full
postgres_env_vars:
- POSTGRES_USER: lemmy
- POSTGRES_PASSWORD: "{{ postgres_password }}"
- POSTGRES_DB: lemmy
lemmy_env_vars:
- RUST_LOG: warn
lemmyui_env_vars:
- LEMMY_UI_LEMMY_INTERNAL_HOST: lemmy:8536
- LEMMY_UI_LEMMY_EXTERNAL_HOST: "{{ domain }}"
- LEMMY_UI_HTTPS: true
postfix_env_vars:
- POSTFIX_myhostname: "{{ domain }}"
pictrs_safety_env_vars:
# Use this in your fedi-safety to allow your worker to authenticate to pictrs-safety
- FEDIVERSE_SAFETY_WORKER_AUTH: "{{ pictrs_safety_worker_auth }}"
- FEDIVERSE_SAFETY_IMGDIR: "/tmp/images"
- USE_SQLITE: 1
- secret_key: "{{ pictrs_safety_secret }}"
- SCAN_BYPASS_THRESHOLD: 10
- MISSING_WORKER_THRESHOLD: 5
Run the Playbook
The last step is to run the playbook, running the command on your personal machine (not the home lab server):
ansible-playbook -i inventory/hosts lemmy.yml --become --ask-become-pass
By default, the nginx component will be listening on port 80 for HTTP traffic and 443 for HTTPS traffic. I decided to bind nginx to port 8480 and 8488 instead because I want to run multiple self-hosted services on my home lab server and have a reverse proxy handle routing my traffic to the various services.
So, now that you’ve ran the playbook, you’ll be able to go to
http://<your server ip>
(or http://<your server ip>:<your port>
if you
customized the nginx port like I did), and you’ll be able to access your own
Lemmy instance! Congratulations!
Accessing Lemmy from the Public Internet
You might, however, be wondering about how can I access this service when I’m not at home, on the same network as my home lab server? Well, as with anything with software, there’s multiple solutions to this, each can be valid for their own goals and use-cases. However, it’s actually a surprisingly complex topic, so I’ve covered this in a separate post: Ingress
There is one lemmy specific thing you’ll want to do here, and that is add
a DNS A
Record that points lemmy.<your-domain>.<your-TLD>
at the public IP
address of the VPS running the reverse proxy.