Lemmy: Run Your Own Federated Reddit-Like Forum
Reddit's API changes in 2023 drove millions of users to look for alternatives. Lemmy is the main self-hosted option: a link aggregator and discussion platform that looks and works like Reddit but runs on the open ActivityPub protocol, which means instances can federate with each other (and with Mastodon, Pleroma, and other Fediverse services).
Photo by Brett Jordan on Unsplash
You can run a private Lemmy instance for your team or community, or join the federated network and participate in communities across thousands of other instances.
How Lemmy's Federation Works
Each Lemmy instance is independent but can talk to other instances:
- A community on
lemmy.worldappears onlemmy.mland vice versa - Users on any instance can post, vote, and comment in any federated community
- Moderation is local — each instance and community has its own moderators
- You can defederate from specific instances (block all content from them)
This means you don't need to run a large instance to have access to content. A small single-user or community instance can still subscribe to communities from major instances like lemmy.world, programming.dev, or beehaw.org.
Installation with Docker Compose
Lemmy requires a few moving parts: the main application, a WebSocket server, a Postgres database, and Pict-RS for image handling.
services:
lemmy:
image: dessalines/lemmy:0.19.5
hostname: lemmy
restart: always
environment:
- RUST_LOG="warn,lemmy_server=info,lemmy_api=info,lemmy_db_schema=info"
volumes:
- ./lemmy.hjson:/config/config.hjson:ro
depends_on:
- postgres
- pictrs
lemmy-ui:
image: dessalines/lemmy-ui:0.19.5
hostname: lemmy-ui
restart: always
environment:
- LEMMY_UI_LEMMY_INTERNAL_HOST=lemmy:8536
- LEMMY_UI_LEMMY_EXTERNAL_HOST=lemmy.yourdomain.com
- LEMMY_UI_HTTPS=true
depends_on:
- lemmy
postgres:
image: postgres:16-alpine
hostname: postgres
restart: always
environment:
- POSTGRES_USER=lemmy
- POSTGRES_PASSWORD=password
- POSTGRES_DB=lemmy
volumes:
- ./volumes/postgres:/var/lib/postgresql/data
pictrs:
image: asonix/pictrs:0.5.16
hostname: pictrs
restart: always
environment:
- PICTRS_OPENTELEMETRY_URL=http://otel:4137
- PICTRS__SERVER__API_KEY=a-secret-key
volumes:
- ./volumes/pictrs:/mnt
lemmy.hjson (main config):
{
hostname: "lemmy.yourdomain.com"
database: {
uri: "postgresql://lemmy:password@postgres/lemmy"
}
pictrs: {
url: "http://pictrs:8080/"
api_key: "a-secret-key"
}
email: {
smtp_server: "mail.yourdomain.com:587"
smtp_login: "[email protected]"
smtp_password: "yourpassword"
smtp_from_address: "[email protected]"
tls_type: "starttls"
}
setup: {
admin_username: "admin"
admin_password: "a-strong-password"
admin_email: "[email protected]"
site_name: "My Lemmy Instance"
}
}
Reverse Proxy
Lemmy needs specific proxy configuration because it serves both a browser app (the UI) and an API/federation endpoint, distinguishing them by Accept header.
Nginx:
upstream lemmy {
server localhost:8536;
}
upstream lemmy-ui {
server localhost:1234;
}
server {
listen 443 ssl;
server_name lemmy.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/lemmy.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/lemmy.yourdomain.com/privkey.pem;
set $proxpass "http://lemmy-ui";
if ($http_accept = "application/activity+json") {
set $proxpass "http://lemmy";
}
if ($http_accept = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
set $proxpass "http://lemmy";
}
if ($request_method = POST) {
set $proxpass "http://lemmy";
}
location / {
proxy_pass $proxpass;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /api {
proxy_pass http://lemmy;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Caddy (simpler approach):
lemmy.yourdomain.com {
@lemmy_api path /api/* /pictrs/* /feeds/* /.well-known/*
@lemmy_api method POST
@lemmy_api header Accept application/activity+json
handle @lemmy_api {
reverse_proxy lemmy:8536
}
handle {
reverse_proxy lemmy-ui:1234
}
}
First-Time Setup
On first launch, Lemmy creates the admin account using the credentials in lemmy.hjson. Log in at your domain to complete setup.
Key admin settings to configure:
- Application question: Optional question users answer when registering (good for spam prevention)
- Registration mode: Open, require application, or closed
- NSFW: Enable or disable NSFW content
- Federation: Enable federation with other instances
To enable federation, you must set it in lemmy.hjson:
federation: {
enabled: true
allowed_instances: [] # empty = allow all
blocked_instances: ["blockedinstance.com"]
}
Creating Your First Community
After logging in as admin, create a community (c/your-community). Set:
- Name: URL-safe identifier (lowercase, hyphens only)
- Display name: Human-readable title
- Language: Restricts posts to that language
- Visibility: Local only (not federated) or public
- Moderation: Who can approve posts, ban users
Joining Other Communities
From your instance, search for communities on other instances:
[email protected] # search for the linux community on lemmy.world
[email protected]
[email protected]
Your instance will subscribe and federate posts from that community.
Use Cases
Private team forum: Close registration, create topic communities (announcements, help, general), replace Slack threads for async discussions with a searchable archive.
Community site: Run a niche community for a specific interest with full control over moderation and federation policies.
Personal instance: A single-user instance lets you participate in the Fediverse with your own domain identity, without depending on any specific provider.
Resources
- Official documentation:
join-lemmy.org/docs - Community browser:
browse.feddit.orgfor discovering communities across instances - Instance list:
lemmy-explorer.tgxn.net
