Introduction

Lemmy is a selfhosted, federated social link aggregation and discussion forum. It consists of many different communities which are focused on different topics. Users can post text, links or images and discuss it with others. Voting helps to bring the most interesting items to the top. There are strong moderation tools to keep out spam and trolls. All this is completely free and open, not controlled by any company. This means that there is no advertising, tracking, or secret algorithms.

Federation is a form of decentralization. Instead of a single central service that everyone uses, there are multiple services that any number of people can use.

A Lemmy website can operate alone. Just like a traditional website, people sign up on it, post messages, upload pictures and talk to each other. Unlike a traditional website, Lemmy instances can interoperate, letting their users communicate with each other; just like you can send an email from your Gmail account to someone from Outlook, Fastmail, Protonmail, or any other email provider, as long as you know their email address, you can mention or message anyone on any website using their address.

Lemmy uses a standardized, open protocol to implement federation which is called ActivityPub. Any software that likewise implements federation via ActivityPub can seamlessly communicate with Lemmy, just like Lemmy instances communicate with one another.

The fediverse ("federated universe") is the name for all instances that can communicate with each other over ActivityPub and the World Wide Web. That includes all Lemmy servers, but also other implementations:

In practical terms: Imagine if you could follow an Facebook group from your Reddit account and comment on its posts without leaving your account. If Facebook and Reddit were federated services that used the same protocol, that would be possible. With a Lemmy account, you can communicate with any other compatible instance, even if it is not running on Lemmy. All that is necessary is that the software support the same subset of the ActivityPub protocol.

Unlike proprietary services, anyone has the complete freedom to run, examine, inspect, copy, modify, distribute, and reuse the Lemmy source code. Just like how users of Lemmy can choose their service provider, you as an individual are free to contribute features to Lemmy or publish a modified version of Lemmy that includes different features. These modified versions, also known as software forks, are required to also uphold the same freedoms as the original Lemmy project. Because Lemmy is libre software that respects your freedom, personalizations are not only allowed but encouraged.

You can contribute to this documentation in the git repository.

This page is adapted from Mastodon documentation under CC BY-SA 4.0.

Choosing an instance

If you are used to sites like Reddit, then Lemmy works in a fundamentally different way. Instead of a single website like reddit.com, there are many different websites (called instances). These are operated by different people, have different topics and rules. Nevertheless, posts created one instance can directly be seen by users who are registered on another. Its basically like email, but for social media.

This means before using Lemmy and registering an account, you need to pick an instance. For this you can browse the instance list and look for one that matches your topics of interest. You can also see if the rules match your expectations, and how many users there are. It is better to avoid very big or very small instances. But don't worry too much about this choice, you can always create another account on a different instance later.

[instance list screenshot]

Registration

Once you chose an instance, it's time to create your account. To do this, click sign up in the top right of the page, or click the top right button on mobile to open a menu with sign up link.

[registration page screenshot]

On the signup page you need to enter a few things:

  • Username: How do you want to be called? This name can not be changed and is unique within an instance. Later you can also set a displayname which can be freely changed. If your desired username is taken, consider choosing a different instance where it is still available.
  • Email: Your email address. This is used for password resets and notifications (if enabled). Providing an email address is usually optional, but admins may choose to make it mandatory. In this case you will have to wait for a confirmation mail and click the link after completing this form.
  • Password: The password for logging in to your account. Make sure to choose a long and unique password which isn't used on any other website.
  • Verify password: Repeat the same password from above to ensure that it was entered correctly.

There are also a few optional fields, which you may need to fill in depending on the instance configuration:

  • Question/Answer: Instance admins can set an arbitrary question which needs to be answered in order to create an account. This is often used to prevent spam bots from signing up. After submitting the form, you will need to wait for some time until the answer is approved manually before you can login.
  • Code: A captcha which is easy to solve for humans but hard for bots. Enter the letters and numbers that you see in the text box, ignoring uppercase or lowercase. Click the refresh button if you are unable to read a character. The play button plays an audio version of the captcha.
  • Show NSFW content: Here you can choose if content that is "not safe for work" (or adult-only) should be shown.

When you are done, press the sign up button.

It depends on the instance configuration when you can login and start using the account. In case the email is mandatory, you need to wait for the confirmation email and click the link first. In case "Question/Answer" is present, you need to wait for an admin to manually review and approve your registration. If you have problems with the registration, try to get in contact with the admin for support. You can also choose a different instance to sign up if your primary choice does not work.

Following communities

After logging in to your new account, its time to follow communities that you are interested in. For this you can click on the communities link at the top of the page (on mobile, you need to click the menu icon on the top right first). You will see a list of communities which can be filtered by subscribed, local or all. Local communities are those which are hosted on the same site where you are signed in, while all also contains federated communities from other instances. In any case you can directly subscribe to communities with the right-hand subscribe link. Or click on the community name to browse the community first, see what its posted and what the rules are before subscribing.

Another way to find communities to subscribe to is by going to the front page and browsing the posts. If there is something that interests you, click on the post title to see more details and comments. Here you can subscribe to the community in the right-hand sidebar, or by clicking the "sidebar" button on mobile.

These previous ways will only show communities that are already known to the instance. Especially if you joined a small or inactive Lemmy instance, there will be few communities to discover. You can find more communities by browsing different Lemmy instances, or using the Lemmy Community Browser. When you found a community that you want to follow, enter its URL (e.g. https://feddit.de/c/main) or the identifier (e.g. !main@feddit.de) into the search field of your own Lemmy instance. Lemmy will then fetch the community from its original instance, and allow you to interact with it. The same method also works to fetch users, posts or comments from other instances.

Setting up your profile

Before you start posting, its a good idea to provide some details about yourself. Open the top-right menu and go to "settings". Here the following settings are available for your public profile:

  • Displayname: An alternative username which can be changed at any time
  • Bio: Long description of yourself, can be formatted with Markdown
  • Matrix User: Your username on the decentralized Matrix chat
  • Avatar: Profile picture that is shown next to all your posts
  • Banner: A header image for your profile page

On this page you can also change the email and password. Additionally there are many other settings available, which allow customizing your browsing experience:

  • Blocks (tab at top of the page): Here you can block users and communities, so that their posts will be hidden.
  • Interface language: Which language the user interface should use.
  • Languages: Select the languages that you speak to see only content in these languages. This is a new feature and many posts don't specify a language yet, so be sure to select "Undetermined" to see them.
  • Theme: You can choose between different color themes for the user interface. Instance admins can add more themes.
  • Type: Which timeline you want to see by default on the frontpage; only posts from communities that you subscribe to, posts in local communities, or all posts including federated.
  • Sort type: How posts and comments should be sorted by default. See [05-votes-and-ranking] for details.
  • Show NSFW content: Whether or not you want to see content that is "not safe for work" (or adult-only).
  • Show Scores: Whether the number of upvotes and downvotes should be visible.
  • Show Avatars: Whether profile pictures of other users should be shown.
  • Bot Account: Enable this if you are using a script or program to create posts automatically
  • Show Bot Accounts: Disable this to hide posts that were created by bot accounts.
  • Show Read Posts: If this is disabled, posts that you already viewed are not shown in listings anymore. Useful if you want to find new content easily, but makes it difficult to follow ongoing discussion under existing posts.
  • Show Notifications for New Posts: Enable this to receive a popup notification for each new post that is created.
  • Send notifications to Email: Enable to receive notifications about new comment replies and private messages to your email address.

Start posting

Finally its time to start posting! To do this it is always a good idea to read the community rules in the sidebar (below the Subscribe button). When you are ready, go to a post and type your comment in the box directly below for a top-level reply. You can also write a nested reply to an existing comment, by clicking the left-pointing arrow.

Other than commenting on existing posts, you can also create new posts. To do this, click the button Create a post in the sidebar. Here you can optionally supply an external link or upload an image. The title field is mandatory and should describe what you are posting. The body is again optional, and gives space for long texts. You can also embed additional images here. The Community dropdown below allows choosing a different community to post in. With NSFW posts can be marked as "not safe for work". Finally you can specify the language that the post is written in, and then click on Create.

One more possibility is to write private messages to individual users. To do this, simply visit a user profile and click Send message. You will be notified about new private messages and comment replies with the bell icon in the top right.

Text

The main type of content in Lemmy is text which can be formatted with Markdown. Refer to the table below for supported formatting rules. The Lemmy user interface also provides buttons for formatting, so it's not necessary to remember all of it. You can also follow the interactive CommonMark tutorial to get started.

TypeOr… to Get
*Italic*_Italic_Italic
**Bold**__Bold__Bold
# Heading 1Heading 1
=========

Heading 1

## Heading 2Heading 2
---------
Heading 2
[Link](http://a.com)[Link][1]

[1]: http://b.org
Link
![Image](http://url/a.png)![Image][1]

[1]: http://url/b.jpg
Markdown
> Blockquote
Blockquote
* List
* List
* List
- List
- List
- List
_ List
_ List
* List
1. One
2. Two
3. Three
1) One
2) Two
3) Three
1. One
2. Two
3. Three
Horizontal Rule
---
Horizontal Rule
***
Horizontal Rule

`Inline code` with backticksInline code with backticks
```
# code block
print '3 backticks or'
print 'indent 4 spaces'
```
····# code block
····print '3 backticks or'
····print 'indent 4 spaces'
# code block
print '3 backticks or'
print 'indent 4 spaces'
::: spoiler hidden or nsfw stuff
a bunch of spoilers here
:::
hidden or nsfw stuff

a bunch of spoilers here

Some subscript textSome subscript text
Some ^superscript^ textSome superscript text

CommonMark Tutorial

Images and video

Lemmy also allows sharing images and videos. To upload an image, go to the Create post page and click the little image icon under the URL field. This allows you to select a local image. If you made a mistake, a popup message allows you to delete the image. The same image button also allows uploading videos in .gif format. Instead of uploading a local file, you can also simply paste the URL of an image or video from another website.

Note that this functionality is not meant to share large images or videos, because that would require too many server resources. Instead, upload them on another platform like Peertube or Pixelfed, and share the link on Lemmy.

Votes and ranking

Lemmy uses a voting system to sort post listings. On the left side of each post are up and down arrows, which let you upvote or downvote it. You can upvote posts that you like so that more users will see them. Or downvote posts so that they are less likely to be seen. Each post receives a score which is the number of upvotes minus number of downvotes.

When browsing the frontpage or a community, you can choose between the following sort types for posts:

  • Active (default): Calculates a rank based on the score and time of the latest comment, with decay over time. See [this page] for more details
  • Hot: Like active, but uses time when the post was published
  • New: Shows most recent posts first
  • Old: Shows oldest posts first
  • Most Comments: Shows posts with highest number of comments first
  • New Comments: Bumps posts to the top when they receive a new reply Analogous to the sorting of traditional forums.
  • Top Day: Highest scoring posts during the last 24 hours
  • Top Week: Highest scoring posts during the last 7 days
  • Top Month: Highest scoring posts during the last 30 days
  • Top Year: Highest scoring posts during the last 12 months
  • Top All Time: Highest scoring posts during all time

Comments are by default arranged in a hierarchy which shows at a glance who it is replying to. Top-level comments which reply directly to a post are on the very left, not indented at all. Comments that are responding to top-level comments are indented one level, and each further level of indentation means that the comment is deeper in the conversation. With this layout it is always easy to see the context for a given comment, simply scroll up to the next comment which is indented one level less.

Comments can be sorted in the following ways. These all keep the indentation intact, so only replies to the same parent are shuffled around.

  • Hot (default): Equivalent to the Hot sort for posts
  • Top: Shows comments with highest score first
  • New: Shows most recent comments first
  • Old: Shows oldest comments first

Additionally there is a sort option Chat. This eliminates the hierarchy, and puts all comments on the top level, with newest comments shown at the top. It is useful to see new replies at any point in the conversation, but makes it difficult to see the context.

Moderation

The internet is full of bots, trolls and other malicious actors. Sooner or later they will post unwanted content to any website that is open to the public. It is the task of administrators and moderators to remove such unwanted content. Lemmy provides many tools for this, from removing individual posts, over temporary bans, to removing all content from an offending user.

Moderation in Lemmy is divided between administrators and moderators. Admins are responsible for the entire instance, and can take action on any content. They are also the only ones who can completely ban users. In contrast, moderators are only responsible for a single community. Where admins can ban a user from the entire instance, mods can only ban them from their community.

The most important thing that normal users can do if they notice a rule breaking post is to use the report function. If you notice such a post, click the flag icon to notify mods and admins. This way they can take action quickly and remove the offending content. To find out about removals and other mod actions, you can use the mod log which is linked at the bottom of the page. In some cases there may be content that you personally dislike, but which doesn't violate any rules. For this exists a block function which hides all posts from a given user or community.

Each instance has a set of rules to let users know which content is allowed or not. These rules can be found in the sidebar and apply to all local communities on that instance. Some communities may have their own rules in the respective sidebar, which apply in addition to the instance rules.

Because Lemmy is decentralized, there is no single moderation team for the platform, nor any platform-wide rules. Instead each instance is responsible to create and enforce its own moderation policy. This means that two Lemmy instances can have rules that completely disagree or even contradict. This can lead to problems if they interact with each other, because by default federation is open to any instance that speaks the same protocol. To handle such cases, administrators can choose to block federation with specific instances. To be even safer, they can also choose to federated only with instances that are allowed explicitly.

How to moderate

To get moderator powers, you either need to create a new community, or be appointed by an existing moderator. Similarly to become an admin, you need to create a new instance, or be appointed by an existing instance admin. Community moderation can be done over federation, you don't need to be registered on the same instance where the community is hosted. To be an instance administrator, you need an account on that specific instance. Admins and moderators are organized in a hierarchy, where the user who is listed first has the power to remove admins or mods who are listed later.

All moderation actions are taken on the context menu of posts or comments. Click the three dot button to expand available mod actions, as shown in the screenshot below. All actions can be reverted in the same way.

moderation_01.png moderation_02.png

ActionResultPermission level
LockPrevents making new comments under the postModerator
Sticky (Community)Pin the publication to the top of the community listingModerator
Sticky (Local)Pin the publication to the top of the frontpageAdmin
RemoveDelete the postModerator
Ban from communityBan user from interacting with the community, but can still use the rest of the site. There is also an option to remove all existing posts.Moderator
Appoint as modGives the user moderator statusModerator
Ban from siteCompletely bans the account, so it can't login or interact at all. There is also an option to remove all existing posts.Admin
Purge userCompletely delete the user, including all posts and uploaded media. Use with caution.Admin
Purge post/commentCompletely delete the post, including attached media.Admin
Appoint as adminGives the user administrator statusAdmin

Censorship resistance

Today's social media landscape is extremely centralised. The vast majority of users are concentrated on only a handful of platforms like Facebook, Reddit or Twitter. All of these are maintained by large corporations that are subject to profit motive and United States law. In recent years these platforms have increasingly censored users and entire communities, often with questionable justifications. It is only natural that those who are affected by this search for alternatives. This document is intended to help with the evaluation.

For this purpose we will consider as censorship anything that prevents a person from expressing their opinion, regardless of any moral considerations. All the options explained here also have legitimate uses, such as deleting spam. Nevertheless it is important for users to understand why their posts are getting removed and how to avoid it.

The first and most common source of censorship in this sense is the admin of a given Lemmy instance. Due to the way federation works, an admin has complete control over his instance, and can arbitrarily delete content or ban users. The moderation log helps to provide transparency into such actions.

The second source of censorship is through legal means. This often happens for copyright violation, but can also be used for other cases. What usually happens in this case is that the instance admin receives a takedown notice from the hosting provider or domain registrar. If the targeted content is not removed within a few days, the site gets taken down. The only way to avoid this is to choose the hosting company and country carefully, and avoid those which might consider the content as illegal.

Another way to censor is through social pressure on admins. This can range from spamming reports for unwanted content, to public posts from influental community members demanding to take certain content down. Such pressure can keep mounting for days or weeks, making it seem like everyone supports these demands. But in fact it is often nothing more than a vocal minority. It is the task of admins to gauge the true opinion of their community. Community members should also push back if a minority tries to impose its views on everyone else.

All of this shows that it is relatively easy to censor a single Lemmy instance. Even a group of instances can be censored if share the same admin team, hosting infrastructure or country. Here it is important that an admin can only censor content on his own instance, or communities which are hosted on his instance. Other instances will be unaffected. So if there is a problem with censorship, it can always be solved by using a different Lemmy instance, or creating a new one.

But what if the goal was to censor the entire Lemmy network? This is inherently difficult because there is no single entity which has control over all instances. The closest thing to such an entity are the developers, because they can make changes to the code that all the instances run. For example, developers could decide to implement a hardcoded block for certain domains, so that they can't federate anymore. However, changes need to be released and then installed by instance admins. Those who are affected would have no reason to upgrade. And because the code is open source, they could publish a forked software version without these blocks. So the effect would be very limited, but it would split the project and result in loss of reputation for the developers. This is probably the reason why it has never happened on any Fediverse platform.

Lastly it might be possible to abuse software vulnerabilities for network-wide censorship. Imagine a bug in Lemmy or in the underlying software stack which allows the attacker to delete arbitrary content. This could remain undetected for a while if used sparingly, but would certainly be discovered after some time. And experience has shown that such critical flaws are fixed very quickly in open source software. It is also highly unlikely that critical vulnerabilities be present in multiple different Fediverse platforms at the same time.

In conclusion, the best way to avoid censorship on Lemmy is through the existince of many independent instances. These should have different admins, different hosting providers and be located in different countries. Additionally users should follow the development process to watch for changes that might create a centralized point of control for all instances. Based on this explanation it should be clear that censorship on Lemmy is difficult, and can always be circumvented. This is in contrast to centralized platforms like Facebook or Reddit. They are not open source and can't be self-hosted, so it is necessary to switch to an entirely different platform to avoid censorship. And due to lack of federation, such a switch means losing contact with users who decide to stay on the censored platform.

Theming

Users can choose between a number of built-in color themes. Admins can also provide additional themes and set them as default.

Easy to install, low hardware requirements

Lemmy is written in Rust, which is an extremely fast language. Thats why it has very low hardware requirements. It can easily run on a Raspberry Pi or similar low-powered hardware. This makes it easy to administrate and keeps costs low.

Language Tags

Lemmy instances and communities can specify which languages can be used for posting. Consider an instance aimed at Spanish users, it would limit the posting language to Spanish so that other languages can't be used. Or an international instance which only allows languages that the admin team understands. Community languages work in the same way, and are restricted to a subset of the instance languages. By default all languages are allowed (including undefined).

Users can also specify which languages they speak, and will only see content in those languages. Lemmy tries to smartly select a default language for new posts if possible. Otherwise you have to specify the language manually.

Lemmy as a blog

Lemmy can also function as a blogging platform. Doing this is as simple as creating a community and enabling the option "Only moderators can post to this community". Now only you and other people that you invite can create posts, while everyone else can comment. Like any Lemmy community, it is also possible to follow from other Fediverse platforms and over RSS. For advanced usage it is even possible to use the API and create a different frontend which looks more blog-like.

History of Lemmy

The idea to make Lemmy was a combination of factors.

Open source developers like myself have long watched the rise of the “Big Five”, the US tech giants that have managed to capture nearly all the world’s everyday communication into their hands. We’ve been asking ourselves why people have moved away from content-focused sites, and what we can do to subvert this trend, in a way that is easily accessible to a non-tech focused audience.

The barriers to entry on the web are much lower than say in the physical world: all it takes is a computer and some coding knowhow… yet the predominating social media firms have been able to stave off competition for at least two reasons: their sites are easy to use, and they have huge numbers of users already (the “first mover” advantage). The latter is more important; if you’ve ever tried to get someone to use a different chat app, you’ll know what I mean.

Now I loved early Reddit, not just for the way that it managed to put all the news for the communities and topics I wanted to see in a single place, but for the discussion trees behind every link posted. I still have many of these saved, and have gained so much more from the discussion behind the links, than I have from the links themselves. In my view, its the community-focused, tree-like discussions, as well as the ability to make, grow, and curate communities, that has made Reddit the 5th most popular site in the US, and where so many people around the world get their news.

But that ship sailed years ago; the early innovative spirit of Reddit left with Aaron Schwartz: its libertarian founders have allowed some of the most racist and sexist online communities to fester on Reddit for years, only occasionally removing them only when community outcry reaches a fever pitch. Reddit closed its source code years ago, and the Reddit redesign has become a bloated anti-privacy mess.

Its become absorbed into that silicon valley surveillance-capitalist machine that commodifies users to sell ads and paid flairs, and propagandizes pro-US interests above all. Software technology being one of the last monopoly exports the US has, it would be naive to think that one of the top 5 most popular social media sites, where so many people around the world get their news, would be anything other than a mouthpiece for the interests of those same US coastal tech firms.

Despite the conservative talking point that big tech is dominated by “leftist propaganda”, it is liberal, and pro-US, not left (leftism referring to the broad category of anti-capitalism). Reddit has banned its share of leftist users and communities, and the Reddit admins via announcement posts repeatedly villify the US’s primary foreign-policy enemies as having “bot campaigns”, and “manipulating Reddit”, yet the default Reddit communities (/r/news, /r/pics, etc), who share a small number of moderators, push a line consistent with US foreign-policy interests. The aptly named /r/copaganda subreddit has exposed the pro-police propaganda that always seems to hit Reddit’s front page in the wake of every tragedy involving US police killing the innocent (or showing police kissing puppies, even though US police kill ~ 30 dogs every day, which researchers have called a “noted statistical phenomenon”).

We’ve also seen a rise in anti-China posts that have hit Reddit lately, and along with that comes anti-chinese racism, which Reddit tacitly encourages. That western countries are seeing a rise in attacks against Asian-Americans, just as some of the perpetrators of several hate-crimes against women were found to be Redditors active in mens-rights Reddit communities, is not lost on us, and we know where these tech companies really stand when it comes to violence and hate speech. Leftists know that our position on these platforms is tenuous at best; we’re currently tolerated, but that will not always be the case.

The idea for making a Reddit alternative seemed pointless, until Mastodon (a federated twitter alternative), started becoming popular. Using Activitypub (a protocol / common language that social media services can use to speak to each other), we finally have a solution to the “first mover” advantage: now someone can build or run a small site, but still be connected to a wider universe of users.

Nutomic and I originally made Lemmy to fill the role as a federated alternative to Reddit, but as it grows, it has the potential become a main source of news and discussion, existing outside of the US’s jurisdictional domain and control.

Administration info

Information for Lemmy instance admins, and those who want to run a server.

If you have any problems in the installation, you can ask for help in !lemmy_support. Do not use Github for support.

Install

Official/Supported methods

Lemmy has two primary installation methods:

We recommend using Ansible, because it simplifies the installation and also makes updating easier.

Lemmy uses roughly 150 MB of RAM in the default Docker installation. CPU usage is negligible.

Other installation methods

⚠️ Under your own risk.

In some cases, it might be necessary to use different installation methods.

You could use any other reverse proxy

An Example Caddy configuration.

Docker Installation

Make sure you have both docker and docker-compose(>=1.24.0) installed. On Ubuntu, just run apt install docker-compose docker.io. Next,

# create a folder for the lemmy files. the location doesnt matter, you can put this anywhere you want
mkdir /lemmy
cd /lemmy

# download default config files
wget https://raw.githubusercontent.com/LemmyNet/lemmy/release/v0.17/docker/prod/docker-compose.yml
wget https://raw.githubusercontent.com/LemmyNet/lemmy/release/v0.17/docker/prod/lemmy.hjson

# Set correct permissions for pictrs folder
mkdir -p volumes/pictrs
sudo chown -R 991:991 volumes/pictrs

If you'd like a different database password, you should also change it in the docker-compose.yml before your first run.

After this, have a look at the config file named lemmy.hjson, and adjust it, in particular the hostname, and possibly the db password. Then run:

docker-compose up -d

You can access the lemmy-ui at http://localhost:80

To make Lemmy available outside the server, you need to setup a reverse proxy, like Nginx. You can use the following simple proxy:

server {
    listen 80;
    server_name my_domain.tld;

    location / {
        proxy_pass http://localhost:LEMMY_PORT;
        proxy_set_header Host $host;
        include proxy_params;
    }
}

You should also setup TLS, for example with Let's Encrypt. Here's a guide for setting up letsencrypt on Ubuntu.

For federation to work, it is important that you do not change any headers that form part of the signature. This includes the Host header - you may need to refer to the documentation for your proxy server to pass through the Host header unmodified.

Updating

To update to the newest version, you can manually change the version in docker-compose.yml. Alternatively, fetch the latest version from our git repo:

wget https://raw.githubusercontent.com/LemmyNet/lemmy/main/docker/docker-compose.yml
docker-compose up -d

Ansible Installation

Follow the instructions on the Lemmy-Ansible repo.

From Scratch

These instructions are written for Ubuntu 20.04.

Installation

Lemmy Backend

It is built from source, so this may take a while, especially on slow devices. For example, Lemmy v0.12.2 takes 17 minutes to build on a dual core VPS. If you prefer prebuilt binaries, use Docker.

Install Rust by following the instructions on Rustup.

Lemmy supports image hosting using pict-rs. We need to install a couple of dependencies for this. You can also skip these steps if you don't require image hosting.

Pict-rs requires the magick command which comes with Imagemagick version 7, but Ubuntu 20.04 only comes with Imagemagick 6. So you need to install that command manually, eg from the official website.

apt install ffmpeg exiftool libgexiv2-dev --no-install-recommends
wget https://download.imagemagick.org/ImageMagick/download/binaries/magick
# compare hash with the "message digest" on the official page linked above
sha256sum magick
mv magick /usr/bin/
chmod 755 /usr/bin/magick

Compile and install Lemmy, setup database:

apt install pkg-config libssl-dev libpq-dev postgresql
# installs latest release, you can also specify one with --version
# The --locked argument uses the exact versions of dependencies specified in
# `cargo.lock`at release time. Running it without the flag will use newer minor
# release versions of those dependencies, which are not always guaranteed to compile.
# Remove the parameter `--features embed-pictrs` if you don't require image hosting.
cargo install lemmy_server --target-dir /usr/bin/ --locked --features embed-pictrs
# replace db-passwd with a randomly generated password
sudo -iu postgres psql -c "CREATE USER lemmy WITH PASSWORD 'db-passwd';"
sudo -iu postgres psql -c "CREATE DATABASE lemmy WITH OWNER lemmy;"
adduser lemmy --system --disabled-login --no-create-home --group

Minimal Lemmy config, put this in /etc/lemmy/lemmy.hjson (see here for more config options). Run chown lemmy:lemmy /etc/lemmy/ -R to set the correct owner.

{
  database: {
    # put your db-passwd from above
    password: "db-passwd"
  }
  # replace with your domain
  hostname: example.com
  bind: "127.0.0.1"
  federation: {
    enabled: true
  }
  # remove this block if you don't require image hosting
  pictrs: {
    url: "http://localhost:8080/"
  }
}

Systemd unit file, so that Lemmy automatically starts and stops, logs are handled via journalctl etc. Put this file into /etc/systemd/system/lemmy.service, then run systemctl enable lemmy and systemctl start lemmy.

[Unit]
Description=Lemmy - A link aggregator for the fediverse
After=network.target

[Service]
User=lemmy
ExecStart=/usr/bin/lemmy_server
Environment=LEMMY_CONFIG_LOCATION=/etc/lemmy/lemmy.hjson
# remove these two lines if you don't need pict-rs
Environment=PICTRS_PATH=/var/lib/pictrs
Environment=PICTRS_ADDR=127.0.0.1:8080
Restart=on-failure

# Hardening
ProtectSystem=yes
PrivateTmp=true
MemoryDenyWriteExecute=true
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

If you did everything right, the Lemmy logs from journalctl -u lemmy should show "Starting http server at 127.0.0.1:8536". You can also run curl localhost:8536/api/{version}/site which should give a successful response, looking like {"site_view":null,"admins":[],"banned":[],"online":0,"version":"unknown version","my_user":null,"federated_instances":null}. For pict-rs, run curl 127.0.0.1:8080 and ensure that it outputs nothing (particularly no errors).

Install lemmy-ui (web frontend)

Install dependencies (nodejs and yarn in Ubuntu 20.04 repos are too old)

# https://classic.yarnpkg.com/en/docs/install/#debian-stable
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
# https://github.com/nodesource/distributions/blob/master/README.md#installation-instructions
curl -fsSL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt install nodejs yarn

Clone the git repo, checkout the version you want (0.16.7 in this case), and compile it.

mkdir /var/lib/lemmy-ui
cd /var/lib/lemmy-ui
chown lemmy:lemmy .
# dont compile as admin
sudo -u lemmy bash
git clone https://github.com/LemmyNet/lemmy-ui.git --recursive .
git checkout 0.16.7 # replace with the version you want to install
yarn install --pure-lockfile
yarn build:prod
exit

Add another systemd unit file, this time for lemmy-ui. You need to replace example.com with your actual domain. Put the file in /etc/systemd/system/lemmy-ui.service, then run systemctl enable lemmy-ui and systemctl start lemmy-ui.

[Unit]
Description=Lemmy UI - Web frontend for Lemmy
After=lemmy.service
Before=nginx.service

[Service]
User=lemmy
WorkingDirectory=/var/lib/lemmy-ui
ExecStart=/usr/bin/node dist/js/server.js
Environment=LEMMY_INTERNAL_HOST=localhost:8536
Environment=LEMMY_EXTERNAL_HOST=example.com
Environment=LEMMY_HTTPS=true
Restart=on-failure

# Hardening
ProtectSystem=full
PrivateTmp=true
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

If everything went right, the command curl -I localhost:1234 should show 200 OK at the top.

Configure reverse proxy and TLS

Install dependencies

apt install nginx certbot python3-certbot-nginx

Request Let's Encrypt TLS certificate (just follow the instructions)

certbot certonly --nginx

Let's Encrypt certificates should be renewed automatically, so add the line below to your crontab, by running sudo crontab -e. Replace example.com with your actual domain.

@daily certbot certonly --nginx --cert-name example.com -d example.com --deploy-hook 'nginx -s reload'

Finally, add the nginx config. After downloading, you need to replace some variables in the file.

curl https://raw.githubusercontent.com/LemmyNet/lemmy-ansible/main/templates/nginx.conf \
    --output /etc/nginx/sites-enabled/lemmy.conf
# put your actual domain instead of example.com
sed -i -e 's/{{domain}}/example.com/g' /etc/nginx/sites-enabled/lemmy.conf
sed -i -e 's/{{lemmy_port}}/8536/g' /etc/nginx/sites-enabled/lemmy.conf
sed -i -e 's/{{lemmy_ui_port}}/1234/g' /etc/nginx/sites-enabled/lemmy.conf
nginx -s reload

Now open your Lemmy domain in the browser, and it should show you a configuration screen. Use it to create the first admin user and the default community.

Upgrading

Lemmy

# installs latest release, you can also specify one with --version
cargo install lemmy_server --target-dir /usr/bin/ --features embed-pictrs
systemctl restart lemmy

Lemmy UI

cd /var/lib/lemmy-ui
sudo -u lemmy
git checkout main
git pull --tags
git checkout 0.12.2 # replace with the version you want to install
git submodule update
yarn install --pure-lockfile
yarn build:prod
exit
systemctl restart lemmy-ui

Pict-rs

rustup update
cd /var/lib/pictrs-source
git checkout main
git pull --tags
# check docker-compose.yml for pict-rs version used by lemmy
# https://github.com/LemmyNet/lemmy-ansible/blob/main/templates/docker-compose.yml#L40
git checkout v0.2.6-r2
# or simply add the bin folder to your $PATH
$HOME/.cargo/bin/cargo build --release
cp target/release/pict-rs /usr/bin/
systemctl restart pictrs

Installing on AWS

⚠️ Disclaimer: this installation method is not recommended by the Lemmy developers. If you have any problems, you need to solve them yourself or ask the respective authors. If you notice any Lemmy bugs on an instance installed like this, please mention it in the bug report.

Lemmy AWS CDK

This contains the necessary infrastructure definitions to deploy Lemmy to AWS using their Cloud Development Kit.

Included:

  • ECS fargate cluster
    • Lemmy-UI
    • Lemmy
    • Pictrs
  • CloudFront CDN
  • EFS storage for image uploads
  • Aurora Serverless Postgres DB
  • Bastion VPC host
  • Load balancers for Lemmy
  • DNS records for your site

Quickstart

Clone the Lemmy-CDK.

Clone Lemmy and Lemmy-UI to the directory above this.

cp example.env.local .env.local
# edit .env.local

You should edit .env.local with your site settings.

npm install -g aws-cdk
npm install
cdk bootstrap
cdk deploy

Cost

This is not the cheapest way to run Lemmy. The Serverless Aurora DB can run you ~$90/mo if it doesn't go to sleep.

Useful CDK commands

  • npm run build compile typescript to js
  • npm run watch watch for changes and compile
  • npm run test perform the jest unit tests
  • cdk deploy deploy this stack to your default AWS account/region
  • cdk diff compare deployed stack with current state
  • cdk synth emits the synthesized CloudFormation template

Administration First Steps

After you successfully installed Lemmy either manually with Docker or automatically with Ansible here are some recommendations for a new administrator of a Lemmy server.

Admin Settings

The first thing to do is to go to your admin panel, which can be found by clicking on the cog at the top right next to the search icon. Here you can define a description for your site, so that people know if it is about one specific topic or if all subjects are welcome. You can also add an icon and a banner that define your server, it can for example be the logo of your organization.

Take the time to browse through the entire page to discover the different options you have to customize your Lemmy instance, on the same page you can edit your configuration file, where you can find information about your database, the email used by the server, the federation options or who is the main administrator.

It is always good to define another administrator than yourself, in case it is necessary to take actions while you take your best nap. Take a look at the moderation guide for more information on how to do this.

Check that everything is working properly

Email

The easiest way to check that the email is set up correctly is to request a password renewal. You will need to set up an email in your settings if you have not already done so.

After that just log out, go to the Login page, enter your email in the Email or Username box and press forgot password. If everything is set up correctly, you should receive an email to renew your password. You can ignore this email.

Federation

Federation is disabled by default, and needs to be enabled either through the online admin panel or directly through the config.json file.

To test that your instance federation is working correctly execute curl -H 'Accept: application/activity+json' https://your-instance.com/u/your-username, it should return json data, and not an .html file. If that is unclear to you, it should look similar to the output of curl -H 'Accept: application/activity+json' https://lemmy.ml/u/nutomic.

Inclusion on join-lemmy.org instance list

To be included in the list of Lemmy instances on join-lemmy.org you must meet the following requirements:

  • Federate with at least one instance from the list
  • Have a site description and icon
  • Be patient and wait the site to be updated, there's no fixed schedule for that

In the meantime you can always promote your server on other social networks like Mastodon using the hashtag #Lemmy.

Keeping up to date

You can subscribe to the Github RSS feeds to be informed of the latest releases:

There is also a Matrix chat for instance administrators that you can join. You'll find some really friendly people there who will help you (or at least try to) if you run into any issue.

Configuration

The configuration is based on the file config.hjson, which is located by default at config/config.hjson. To change the default location, you can set the environment variable LEMMY_CONFIG_LOCATION.

An additional environment variable LEMMY_DATABASE_URL is available, which can be used with a PostgreSQL connection string like postgres://lemmy:password@lemmy_db:5432/lemmy, passing all connection details at once.

If the Docker container is not used, manually create the database specified above by running the following commands:

cd server
./db-init.sh

Federation is not set up by default. You can add this this federation block to your lemmy.hjson, and ask other servers to add you to their allowlist.

Full config with default values

{
  # settings related to the postgresql database
  database: {
    # Username to connect to postgres
    user: "lemmy"
    # Password to connect to postgres
    password: "password"
    # Host where postgres is running
    host: "localhost"
    # Port where postgres can be accessed
    port: 5432
    # Name of the postgres database for lemmy
    database: "lemmy"
    # Maximum number of active sql connections
    pool_size: 5
  }
  # Settings related to activitypub federation
  # Pictrs image server configuration.
  pictrs: {
    # Address where pictrs is available (for image hosting)
    url: "http://localhost:8080/"
    # Set a custom pictrs API key. ( Required for deleting images )
    api_key: "string"
  }
  # Email sending configuration. All options except login/password are mandatory
  email: {
    # Hostname and port of the smtp server
    smtp_server: "localhost:25"
    # Login name for smtp server
    smtp_login: "string"
    # Password to login to the smtp server
    smtp_password: "string"
    # Address to send emails from, eg "noreply@your-instance.com"
    smtp_from_address: "noreply@example.com"
    # Whether or not smtp connections should use tls. Can be none, tls, or starttls
    tls_type: "none"
  }
  # Parameters for automatic configuration of new instance (only used at first start)
  setup: {
    # Username for the admin user
    admin_username: "admin"
    # Password for the admin user. It must be at least 10 characters.
    admin_password: "tf6HHDS4RolWfFhk4Rq9"
    # Name of the site (can be changed later)
    site_name: "My Lemmy Instance"
    # Email for the admin user (optional, can be omitted and set later through the website)
    admin_email: "user@example.com"
  }
  # the domain name of your instance (mandatory)
  hostname: "unset"
  # Address where lemmy should listen for incoming requests
  bind: "0.0.0.0"
  # Port where lemmy should listen for incoming requests
  port: 8536
  # Whether the site is available over TLS. Needs to be true for federation to work.
  tls_enabled: true
}

Lemmy-UI configuration

Lemmy-UI can be configured using environment variables, detailed in its README.

Theming Guide

Lemmy uses Bootstrap v4, and very few custom css classes, so any bootstrap v4 compatible theme should work fine. Use a tool like bootstrap.build to create a bootstrap v4 theme. Export the bootstrap.min.css once you're done, and save the _variables.scss too.

If you installed Lemmy with Docker, save your theme file to ./volumes/lemmy-ui/extra_themes. For native installation (without Docker), themes are loaded by lemmy-ui from ./extra_themes folder. A different path can be specified with LEMMY_UI_EXTRA_THEMES_FOLDER environment variable.

After a theme is added, users can select it under /settings. Admins can set a theme as site default under /admin.

Federation

Lemmy has three types of federation:

  • Allowlist: Explicitly list instances to connect to.
  • BlockList: Explicitly list instances to not connect to. Federation is open to all other instances.
  • Open: Federate with all potential instances.

Federation is enabled by default. You can add allowed and blocked instances, by adding a comma-delimited list in your instance admin panel. IE to only federate with these instances, add: enterprise.lemmy.ml,lemmy.ml to the allowed instances section.

Lemmy uses the ActivityPub protocol (a W3C standard) to enable federation between different servers (often called instances). This is very similar to the way email works. For example, if you use gmail.com, then you can not only send mails to other gmail.com users, but also to yahoo.com, yandex.ru and so on. Email uses the SMTP protocol to achieve this, so you can think of ActivityPub as "SMTP for social media". The amount of different actions possible on social media (post, comment, like, share, etc) means that ActivityPub is much more complicated than SMTP.

As with email, ActivityPub federation happens only between servers. So if you are registered on enterprise.lemmy.ml, you only connect to the API of enterprise.lemmy.ml, while the server takes care of sending and receiving data from other instances (eg voyager.lemmy.ml). The great advantage of this approach is that the average user doesn't have to do anything to use federation. In fact if you are using Lemmy, you are likely already using it. One way to confirm is by going to a community or user profile. If you are on enterprise.lemmy.ml and you see a user like @nutomic@voyager.lemmy.ml, or a community like !main@ds9.lemmy.ml, then those are federated, meaning they use a different instance from yours.

One way you can take advantage of federation is by opening a different instance, like ds9.lemmy.ml, and browsing it. If you see an interesting community, post or user that you want to interact with, just copy its URL and paste it into the search of your own instance. Your instance will connect to the other one (assuming the allowlist/blocklist allows it), and directly display the remote content to you, so that you can follow a community or comment on a post. Here are some examples of working searches:

  • !main@lemmy.ml (Community)
  • @nutomic@lemmy.ml (User)
  • https://lemmy.ml/c/programming (Community)
  • https://lemmy.ml/u/nutomic (User)
  • https://lemmy.ml/post/123 (Post)
  • https://lemmy.ml/comment/321 (Comment)

You can see the list of linked instances by following the "Instances" link at the bottom of any Lemmy page.

Fetching communities

If you search for a community first time, 20 posts are fetched initially. Only if a least one user on your instance subscribes to the remote community, will the community send updates to your instance. Updates include:

  • New posts, comments
  • Votes
  • Post, comment edits and deletions
  • Mod actions

You can copy the URL of the community from the address bar in your browser and insert it in your search field. Wait a few seconds, the post will appear below. At the moment there is no loading indicator for the search, so wait a few seconds if it shows "no results".

Fetching posts

Paste the URL of a post into your Lemmy instance's search field. Wait a few seconds until the post appears. This will also fetch the community profile, and the profile of the post creator.

Fetching comments

If you find an interesting comment under a posting on another instance, you can find below the comment in the 3-dot-menu the link-symbol. Copy this link. It looks like https://lemmy.ml/post/56382/comment/40796. Remove the post/XXX part and put it into your search-bar. For this example, search for https://lemmy.ml/comment/40796. This comment, all parent comments, users and community and the corresponding post are fetched from the remote instance, if they are not known locally.

Sibling comments are not fetched! If you want more comments from older posts, you have to search for each of them as described above.

Troubleshooting

Different problems that can occur on a new instance, and how to solve them.

Many Lemmy features depend on a correct reverse proxy configuration. Make sure yours is equivalent to our nginx config.

General

Logs

For frontend issues, check the browser console for any error messages.

For server logs, run docker-compose logs -f lemmy in your installation folder. You can also do docker-compose logs -f lemmy lemmy-ui pictrs to get logs from different services.

If that doesn't give enough info, try changing the line RUST_LOG=error in docker-compose.yml to RUST_LOG=info or RUST_LOG=verbose, then do docker-compose restart lemmy.

Creating admin user doesn't work

Make sure that websocket is working correctly, by checking the browser console for errors. In nginx, the following headers are important for this:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

Rate limit error when many users access the site

Check that the headers X-Real-IP and X-Forwarded-For are sent to Lemmy by the reverse proxy. Otherwise, it will count all actions towards the rate limit of the reverse proxy's IP. In nginx it should look like this:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Federation

Other instances can't fetch local objects (community, post, etc)

Your reverse proxy (eg nginx) needs to forward requests with header Accept: application/activity+json to the backend. This is handled by the following lines:

set $proxpass "http://0.0.0.0:{{ lemmy_ui_port }}";
if ($http_accept = "application/activity+json") {
set $proxpass "http://0.0.0.0:{{ lemmy_port }}";
}
if ($http_accept = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
set $proxpass "http://0.0.0.0:{{ lemmy_port }}";
}
proxy_pass $proxpass;

You can test that it works correctly by running the following commands, all of them should return valid JSON:

curl -H "Accept: application/activity+json" https://your-instance.com/u/some-local-user
curl -H "Accept: application/activity+json" https://your-instance.com/c/some-local-community
curl -H "Accept: application/activity+json" https://your-instance.com/post/123 # the id of a local post
curl -H "Accept: application/activity+json" https://your-instance.com/comment/123 # the id of a local comment

Fetching remote objects works, but posting/commenting in remote communities fails

Check that federation is allowed on both instances.

Also ensure that the time is accurately set on your server. Activities are signed with a timestamp, and will be discarded if it is off by more than 10 seconds.

Other instances don't receive actions reliably

Lemmy uses a queue to send out activities. The size of this queue is specified by the config value federation.worker_count. Very large instances might need to increase this value. Search the logs for "Activity queue stats", if it is consistently larger than the worker_count (default: 64), the count needs to be increased.

Backup and Restore Guide

Docker and Ansible

When using docker or ansible, there should be a volumes folder, which contains both the database, and all the pictures. Copy this folder to the new instance to restore your data.

Incremental Database backup

To incrementally backup the DB to an .sql.gz file, you can run:

docker-compose exec postgres pg_dumpall -c -U lemmy | gzip > lemmy_dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql.gz

For compression, you can use either gzip and gunzip, or xz and unxz.

A Sample backup script

#!/bin/sh
# DB Backup
ssh MY_USER@MY_IP "docker-compose exec postgres pg_dumpall -c -U lemmy" | gzip > ~/BACKUP_LOCATION/INSTANCE_NAME_dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql.gz

# Volumes folder Backup
rsync -avP -zz --rsync-path="sudo rsync" MY_USER@MY_IP:/LEMMY_LOCATION/volumes ~/BACKUP_LOCATION/FOLDERNAME

Restoring the DB

To restore, run:

docker-compose up -d postgres

# Restore from the .sql.gz backup
gunzip < db_dump.sql  |  docker-compose exec -T postgres psql -U lemmy

If you've accidentally already started the lemmy service, you need to clear out your existing database:

# Drop the existing DB
docker exec -i FOLDERNAME_postgres_1 psql -U lemmy -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"

# This also might be necessary when doing a db import with a different password.
docker exec -i FOLDERNAME_postgres_1 psql -U lemmy -c "alter user lemmy with password 'bleh'"

Then run the restore commands above.

Changing your domain name

If you haven't federated yet, you can change your domain name in the DB. Warning: do not do this after you've federated, or it will break federation.

Get into psql for your docker:

docker-compose exec postgres psql -U lemmy

-- Post
update post set ap_id = replace (ap_id, 'old_domain', 'new_domain');
update post set url = replace (url, 'old_domain', 'new_domain');
update post set body = replace (body, 'old_domain', 'new_domain');
update post set thumbnail_url = replace (thumbnail_url, 'old_domain', 'new_domain');

-- Comments
update comment set ap_id = replace (ap_id, 'old_domain', 'new_domain');
update comment set content = replace (content, 'old_domain', 'new_domain');

-- User
update user_ set actor_id = replace (actor_id, 'old_domain', 'new_domain');
update user_ set inbox_url = replace (inbox_url, 'old_domain', 'new_domain');
update user_ set shared_inbox_url = replace (shared_inbox_url, 'old_domain', 'new_domain');
update user_ set avatar = replace (avatar, 'old_domain', 'new_domain');

-- Community
update community set actor_id = replace (actor_id, 'old_domain', 'new_domain');
update community set followers_url = replace (followers_url, 'old_domain', 'new_domain');
update community set inbox_url = replace (inbox_url, 'old_domain', 'new_domain');
update community set shared_inbox_url = replace (shared_inbox_url, 'old_domain', 'new_domain');

More resources

  • https://stackoverflow.com/questions/24718706/backup-restore-a-dockerized-postgresql-database

Using Caddy as reverse proxy example

If you prefer to use Caddy instead of Nginx - you could use this template to fit into your needs:

(caddy-common) {
    encode gzip
    header {
        -Server
        Strict-Transport-Security "max-age=31536000; include-subdomains;"
        X-XSS-Protection "1; mode=block"
        X-Frame-Options "DENY"
        X-Content-Type-Options nosniff
        Referrer-Policy  no-referrer-when-downgrade
        X-Robots-Tag "none"
    }
}

lemmy-site.com {
        import caddy-common
        reverse_proxy   http://lemmy_lemmy-ui_1:1234
}

@lemmy {
        path    /api/*
        path    /pictrs/*
        path    /feeds/*
        path    /nodeinfo/*
        path    /.well-known/*
}

@lemmy-hdr {
        header Accept application/*
}

handle @lemmy {
        reverse_proxy   http://lemmy_lemmy_1:8536
}

handle @lemmy-hdr {
        reverse_proxy   http://lemmy_lemmy_1:8536
}

@lemmy-post {
        method POST
}

handle @lemmy-post {
        reverse_proxy   http://lemmy_lemmy_1:8536
}

Contributing

Lemmy is an open source project and relies on community contributions to get better. Development happens mainly in the Lemmy Github repositories. Communication is done over Matrix.

These are the main repositories which are relevant for contributors:

  • lemmy: The backend which is the core of Lemmy. It implements SQL queries, provides the API and handles ActivityPub federation. Additionally it sends emails and provides RSS feeds. Written in Rust with actix-web and diesel. The issue tracker is also used for general enhancements which affect multiple repositories.
  • lemmy-ui: The main frontend for Lemmy. It provides the user interface that you see when viewing a Lemmy instance. Written in Typescript and CSS with the Inferno framework.
  • lemmy-ansible: Automated installation method which is recommended for users without technical knowledge.
  • joinlemmy-site: Source code for the official project website join-lemmy.org. Landing page for new users which includes general information and a list of instances.
  • lemmy-js-client: Client for the Lemmy API which is used by lemmy-ui. Can also be used by other projects to get started more easily.
  • activitypub-federation-rust: High-level framework for ActivityPub federation in Rust. Was originally part of the Lemmy code, but was extracted and made more generic so that other projects can use it too.

There are many different ways to contribute, depending on your skills and interests:

Reporting issues

You may notice different problems or potential improvements when using Lemmy. You can report them in the relevant repository. Make sure to first search the issue tracker to avoid duplicates. When creating the issue, fill in the template and include as much relevant information as possible.

Translating

Use Weblate to help translate Lemmy into different languages.

Programming and Design

You can open a pull request to make changes to Lemmy. In case of bigger contributions it is recommended to discuss it in an issue first. See the next sections for instructions to compile and develop the projects.

Donating

Besides contributing with your time, you can also consider making a donation to support the developers.

Local Development

Install build requirements

Install the latest Rust version using rustup.

Debian-based distro:

sudo apt install git cargo libssl-dev pkg-config libpq-dev curl
# install yarn
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update && sudo apt install yarn

Arch-based distro:

sudo pacman -S git cargo libssl-dev pkg-config libpq-dev curl
# install yarn (stable)
curl -o- -L https://yarnpkg.com/install.sh | bash

macOS:

Install Homebrew if you don't already have it installed. Then install Node and Yarn.

brew install node yarn

Setup PostgreSQL database

Debian-based disto:

sudo apt install postgresql
sudo systemctl start postgresql

Arch-based distro:

sudo pacman -S postgresql
sudo systemctl start postgresql

macOS:

brew install postgresql
brew services start postgresql
/usr/local/opt/postgres/bin/createuser -s postgres

Either execute scripts/db-init.sh, or manually initialize the postgres database:

psql -c "create user lemmy with password 'password' superuser;" -U postgres
psql -c 'create database lemmy with owner lemmy;' -U postgres
export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy

Get the code

Clone frontend and backend code to local folders. Be sure to include --recursive to initialize git submodules.

git clone https://github.com/LemmyNet/lemmy.git --recursive
git clone https://github.com/LemmyNet/lemmy-ui.git --recursive

Backend development

Use cargo check to find compilation errors. To start the Lemmy backend, run cargo run. It will bind to 0.0.0.0:8536.

After making changes, you need to format the code with cargo +nightly fmt --all and run the linter with ./scripts/fix-clippy.sh.

Frontend development

Install dependencies by running yarn. Then run yarn start to launch lemmy-ui locally. It automatically connects to the Lemmy backend on localhost:8536. Open localhost:1234 in your browser. The project is rebuilt automatically when you change any files.

Note that this setup doesn't support image uploads. If you want to test those, you need to use the Docker development.

Tests

Run Rust unit tests:

./scripts/test.sh

To run federation/API tests, first add the follwing lines to /etc/hosts:

127.0.0.1       lemmy-alpha
127.0.0.1       lemmy-beta
127.0.0.1       lemmy-gamma
127.0.0.1       lemmy-delta
127.0.0.1       lemmy-epsilon

Then run the following script:

cd api_tests
./run-federation-test.bash

Docker Development

Dependencies

Debian-based distro:

sudo apt install git docker-compose
sudo systemctl start docker
git clone https://github.com/LemmyNet/lemmy --recursive

Arch-based distro:

sudo pacman -S git docker-compose
sudo systemctl start docker

Get the code with submodules:

git clone https://github.com/LemmyNet/lemmy --recursive

Running

cd docker
./docker_update.sh

Then open localhost:1236 in your browser.

Building with Docker is relatively slow. To get faster builds you need to use local development instead.

Federation Development

The federation setup allows starting a few local Lemmy instances, to test federation functionality. You can start it with the following commands:

cd docker/federation
./start-local-instances.bash

The federation test sets up 5 instances:

InstanceAdmin usernameLocationNotes
lemmy-alphalemmy_alpha127.0.0.1:8540federated with all other instances
lemmy-betalemmy_beta127.0.0.1:8550federated with all other instances
lemmy-gammalemmy_gamma127.0.0.1:8560federated with all other instances
lemmy-deltalemmy_delta127.0.0.1:8570only allows federation with lemmy-beta
lemmy-epsilonlemmy_epsilon127.0.0.1:8580uses blocklist, has lemmy-alpha blocked

You can log into each using the instance name, and lemmy as the password, IE (lemmy_alpha, lemmy).

To start federation between instances, visit one of them and search for a user, community or post, like this. Note that the Lemmy backend runs on a different port than the frontend, so you have to increment the port number from the URL bar by one.

  • http://lemmy-gamma:8561/u/lemmy-gamma
  • http://lemmy-alpha:8541/c/main
  • http://lemmy-beta:8551/post/3

API

Lemmy has an HTTP API for clients and frontends. See the API documentation for more information. Instead of using the API directly you can use one of the existing libraries. You can either interact with a local development instance via http://localhost:8536, or connect to a production instance. The following instances are available for testing purposes:

  • https://enterprise.lemmy.ml/
  • https://ds9.lemmy.ml/
  • https://voyager.lemmy.ml/

Curl Examples

GET example

The current api {version} is here.

curl "https://lemmy.ml/api/{version}/community/list?sort=Hot"`

POST example

curl -i -H \
"Content-Type: application/json" \
-X POST \
-d '{
  "comment_id": 374,
  "score": 1,
  "auth": eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MiwiaXNzIjoidGVzdC5sZW1teS5tbCJ9.P77RX_kpz1a_geY5eCp29sl_5mAm-k27Cwnk8JcIZJk
}' \
https://lemmy.ml/api/{version}/comment/like

RSS/Atom feeds

  • All - /feeds/all.xml?sort=Hot
  • Community - /feeds/c/community-name.xml?sort=Hot
  • User - /feeds/u/user-name.xml?sort=Hot

Images

Lemmy forwards image requests to a locally running Pictrs.

GET /pictrs/image/{filename}?format={webp, jpg, ...}&thumbnail={96}

Format and thumbnail are optional.

Create (request)

Uploaded content must be valid multipart/form-data with an image array located within the images[] key.

POST /pictrs/image

Create (response)

{
  "files": [
    {
      "delete_token": "{token}",
      "file": "{file}.jpg"
    }
  ],
  "msg": "ok"
}

Delete

GET /pictrs/image/delete/{delete_token}/{file}

Rust API

If you want to develop a Rust application which interacts with Lemmy, you can directly pull in the relevant API structs. This uses the exact API structs used in Lemmy, but with most heavyweight dependencies disabled. API paths or HTTP client are not included, so you need to handle those aspects manually. To get started, run cargo add lemmy_api_common in your repository. You can then use the following code to make an API request:


#![allow(unused)]
fn main() {
use lemmy_api_common::post::{GetPosts, GetPostsResponse};
use lemmy_db_schema::{ListingType, SortType};
use ureq::Agent;

pub fn list_posts() -> GetPostsResponse {
    let params = GetPosts {
        type_: Some(ListingType::Local),
        sort: Some(SortType::New),
        ..Default::default()
    };
    Agent::new()
        .get("https://lemmy.ml/api/v3/post/list")
        .send_json(&params).unwrap()
        .into_json().unwrap()
}
}

You can also look at the following real-world projects as examples:

Creating a Custom Frontend

The Lemmy backend and frontend are completely seperate projects. This creates a lot of potential for alternative frontends which can change much of the design and user experience of Lemmy. For example, it is possible to create a frontend in the style of a traditional forum like phpBB, a question-and-answer site like stackoverflow, a blogging platform or an image gallery. This way you don't have to write any SQL queries, federation logic, API code and so on, but can use the proven implementation from Lemmy. It is also possible to run multiple frontends for a single Lemmy instance.

Development

The easiest way to get started is by forking one of the existing frontends. But you can also create a new frontend from scratch. In any case the principle is the same: bind to a port to serve user requests, and connect to the API of a Lemmy instance as described above to fetch data.

Translations

You can add the lemmy-translations repository to your project as a git submodule. That way you can take advantage of same translations used in the official frontend, and you will also receive new translations contributed via weblate.

Rate limiting

Lemmy does rate limiting for many actions based on the client IP. But if you make any API calls on the server side (e.g. in the case of server-side rendering, or javascript pre-rendering), Lemmy will take the IP of the Docker container. Meaning that all requests come from the same IP, and get rate limited much earlier. To avoid this problem, you need to pass the actual client IP via Forwarded or X-Forwarded-For HTTP header.

Federation

Lemmy uses the ActivityPub protocol for communication between servers. If you are unfamiliar with the protocol, you can start by reading the resource links. This document explains how to interact with it from other projects.

In Lemmy we use some specific terms to refer to ActivityPub items. They are essentially our specific implementations of well-known ActivityPub concepts:

  • Community: Group
  • User: Person
  • Post: Page
  • Comment: Note

Almost every action in Lemmy happens inside a group. The Federation Enhancement Proposal Group Federation gives a high-level overview how this works. The generic federation logic is implemented in the activitypub-federation library. It can also be used by other Rust projects.

Sometimes you will see a notation like Create/Note. This refers to a Create activity with a Note as object.

Below are explanations and examples for all actors, objects and activities from Lemmy. These include many optional fields which you can safely ignore.

Context

[
  "https://www.w3.org/ns/activitystreams",
  "https://w3id.org/security/v1",
  {
    "lemmy": "https://join-lemmy.org/ns#",
    "litepub": "http://litepub.social/ns#",
    "pt": "https://joinpeertube.org/ns#",
    "sc": "http://schema.org/",
    "ChatMessage": "litepub:ChatMessage",
    "commentsEnabled": "pt:commentsEnabled",
    "sensitive": "as:sensitive",
    "matrixUserId": "lemmy:matrixUserId",
    "postingRestrictedToMods": "lemmy:postingRestrictedToMods",
    "removeData": "lemmy:removeData",
    "stickied": "lemmy:stickied",
    "moderators": {
      "@type": "@id",
      "@id": "lemmy:moderators"
    },
    "expires": "as:endTime",
    "distinguished": "lemmy:distinguished",
    "language": "sc:inLanguage",
    "identifier": "sc:identifier"
  }
]

The context is identical for all activities and objects.

Actors

Community

An automated actor. Users can send posts or comments to it, which the community forwards to its followers in the form of Announce.

{
  "id": "https://enterprise.lemmy.ml/c/tenforward",
  "type": "Group",
  "preferredUsername": "main",
  "name": "Ten Forward",
  "summary": "<p>Lounge and recreation facility</p>\n<hr />\n<p>Welcome to the <a href=\"https://memory-alpha.fandom.com/wiki/USS_Enterprise_(NCC-1701-D)\">Enterprise</a>!.</p>\n",
  "source": {
    "content": "Lounge and recreation facility\n\n---\n\nWelcome to the [Enterprise](https://memory-alpha.fandom.com/wiki/USS_Enterprise_(NCC-1701-D))!.",
    "mediaType": "text/markdown"
  },
  "sensitive": false,
  "icon": {
    "type": "Image",
    "url": "https://enterprise.lemmy.ml/pictrs/image/waqyZwLAy4.webp"
  },
  "image": {
    "type": "Image",
    "url": "https://enterprise.lemmy.ml/pictrs/image/Wt8zoMcCmE.jpg"
  },
  "inbox": "https://enterprise.lemmy.ml/c/tenforward/inbox",
  "followers": "https://enterprise.lemmy.ml/c/tenforward/followers",
  "moderators": "https://enterprise.lemmy.ml/c/tenforward/moderators",
  "attributedTo": "https://enterprise.lemmy.ml/c/tenforward/moderators",
  "featured": "https://enterprise.lemmy.ml/c/tenforward//featured",
  "postingRestrictedToMods": false,
  "endpoints": {
    "sharedInbox": "https://enterprise.lemmy.ml/inbox"
  },
  "outbox": "https://enterprise.lemmy.ml/c/tenforward/outbox",
  "publicKey": {
    "id": "https://enterprise.lemmy.ml/c/tenforward#main-key",
    "owner": "https://enterprise.lemmy.ml/c/tenforward",
    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzRjKTNtvDCmugplwEh+g\nx1bhKm6BHUZfXfpscgMMm7tXFswSDzUQirMgfkxa9ubfr1PDFKffA2vQ9x6CyuO/\n70xTafdOHyV1tSqzgKz0ZvFZ/VCOo6qy1mYWVkrtBm/fKzM+87MdkKYB/zI4VyEJ\nLfLQgjwxBAEYUH3CBG71U0gO0TwbimWNN0vqlfp0QfThNe1WYObF88ZVzMLgFbr7\nRHBItZjlZ/d8foPDidlIR3l2dJjy0EsD8F9JM340jtX7LXqFmU4j1AQKNHTDLnUF\nwYVhzuQGNJ504l5LZkFG54XfIFT7dx2QwuuM9bSnfPv/98RYrq1Si6tCkxEt1cVe\n4wIDAQAB\n-----END PUBLIC KEY-----\n"
  },
  "language": [
    {
      "identifier": "fr",
      "name": "Français"
    },
    {
      "identifier": "de",
      "name": "Deutsch"
    }
  ],
  "published": "2019-06-02T16:43:50.799554+00:00",
  "updated": "2021-03-10T17:18:10.498868+00:00"
}
Field NameDescription
preferredUsernameName of the actor
nameTitle of the community
sensitiveTrue indicates that all posts in the community are nsfw
attributedToFirst the community creator, then all the remaining moderators
summaryText for the community sidebar, usually containing a description and rules
iconIcon, shown next to the community name
imageBanner image, shown on top of the community page
inboxActivityPub inbox URL
outboxActivityPub outbox URL, only contains up to 20 latest posts, no comments, votes or other activities
followersFollower collection URL, only contains the number of followers, no references to individual followers
endpointsContains URL of shared inbox
publishedDatetime when the community was first created
updatedDatetime when the community was last changed
publicKeyThe public key used to verify signatures from this actor

User

A person, interacts primarily with the community where it sends and receives posts/comments. Can also create and moderate communities, and send private messages to other users. Can be followed from other platforms.

{
  "id": "https://enterprise.lemmy.ml/u/picard",
  "type": "Person",
  "preferredUsername": "picard",
  "name": "Jean-Luc Picard",
  "summary": "<p>Captain of the starship <strong>Enterprise</strong>.</p>\n",
  "source": {
    "content": "Captain of the starship **Enterprise**.",
    "mediaType": "text/markdown"
  },
  "icon": {
    "type": "Image",
    "url": "https://enterprise.lemmy.ml/pictrs/image/ed9ej7.jpg"
  },
  "image": {
    "type": "Image",
    "url": "https://enterprise.lemmy.ml/pictrs/image/XenaYI5hTn.png"
  },
  "matrixUserId": "@picard:matrix.org",
  "inbox": "https://enterprise.lemmy.ml/u/picard/inbox",
  "outbox": "https://enterprise.lemmy.ml/u/picard/outbox",
  "endpoints": {
    "sharedInbox": "https://enterprise.lemmy.ml/inbox"
  },
  "published": "2020-01-17T01:38:22.348392+00:00",
  "updated": "2021-08-13T00:11:15.941990+00:00",
  "publicKey": {
    "id": "https://enterprise.lemmy.ml/u/picard#main-key",
    "owner": "https://enterprise.lemmy.ml/u/picard",
    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0lP99/s5Vv+XbPdkeqIJ\nwoD4GFnHmBnBHdEKChEUWfWj1TtioC/rGNoXFQeXQA3Amhy4nxSceiDnUgwkkuQY\nv0MtIW58NzgknEavtllxL+LSds5pg3gANaDIk8UiWTkqXTg0GnlJMpCK1Chen0l/\nszL6DEvUyTSuS5ZYDXFgewF89Pe7U0S15V5U2Harv7AgJYDyxmUL0D1pGuUCRqcE\nl5MTHJjrXeNnH1w2g8aly8YlO/Cr0L51rFg/lBF23vni7ZLv8HbmWh6YpaAf1R8h\nE45zKR7OHqymdjzrg1ITBwovefpwMkVgnJ+Wdr4HPnFlBSkXPoZeM11+Z8L0anzA\nXwIDAQAB\n-----END PUBLIC KEY-----\n"
  }
}
Field NameDescription
preferredUsernameName of the actor
nameThe user's displayname
summaryUser bio
iconThe user's avatar, shown next to the username
imageThe user's banner, shown on top of the profile
inboxActivityPub inbox URL
endpointsContains URL of shared inbox
publishedDatetime when the user signed up
updatedDatetime when the user profile was last changed
publicKeyThe public key used to verify signatures from this actor

Instance

Represents a Lemmy instance, and is used to federate global data like the instance description or site bans. It can be fetched from the root path.

{
  "type": "Application",
  "id": "https://enterprise.lemmy.ml/",
  "name": "Enterprise",
  "summary": "A test instance",
  "content": "<p>Enterprise sidebar</p>\\n",
  "mediaType": "text/html",
  "source": {
    "content": "Enterprise sidebar",
    "mediaType": "text/markdown"
  },
  "inbox": "https://enterprise.lemmy.ml/inbox",
  "outbox": "https://enterprise.lemmy.ml/outbox",
  "publicKey": {
    "id": "https://enterprise.lemmy.ml/#main-key",
    "owner": "https://enterprise.lemmy.ml/",
    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAupcK0xTw5yQb/fnztAmb\n9LfPbhJJP1+1GwUaOXGYiDJD6uYJhl9CLmgztLl3RyV9ltOYoN8/NLNDfOMmgOjd\nrsNWEjDI9IcVPmiZnhU7hsi6KgQvJzzv8O5/xYjAGhDfrGmtdpL+lyG0B5fQod8J\n/V5VWvTQ0B0qFrLSBBuhOrp8/fTtDskdtElDPtnNfH2jn6FgtLOijidWwf9ekFo4\n0I1JeuEw6LuD/CzKVJTPoztzabUV1DQF/DnFJm+8y7SCJa9jEO56Uf9eVfa1jF6f\ndH6ZvNJMiafstVuLMAw7C/eNJy3ufXgtZ4403oOKA0aRSYf1cc9pHSZ9gDE/mevH\nLwIDAQAB\n-----END PUBLIC KEY-----\n"
  },
  "language": [
    {
      "identifier": "fr",
      "name": "Français"
    },
    {
      "identifier": "es",
      "name": "Español"
    }
  ],
  "published": "2022-01-19T21:52:11.110741+00:00"
}
Field NameDescription
nameInstance name
summaryShort description
contentLong description (sidebar)
iconInstance icon
imageInstance banner
inboxActivityPub inbox URL
endpointsContains URL of shared inbox
publishedDatetime when the instance was created
updatedDatetime when the instance metadata
publicKeyThe public key used to verify signatures from this actor

Objects

Post

A page with title, and optional URL and text content. The attachment URL often leads to an image, in which case a thumbnail is included. Each post belongs to exactly one community. Sent out as Page, but for receiving the types Article, Note, Video and Event are also accepted.

{
  "id": "https://enterprise.lemmy.ml/post/55143",
  "type": "Page",
  "attributedTo": "https://enterprise.lemmy.ml/u/picard",
  "to": [
    "https://enterprise.lemmy.ml/c/tenforward",
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "audience": "https://enterprise.lemmy.ml/c/tenforward",
  "name": "Post title",
  "content": "<p>This is a post in the /c/tenforward community</p>\n",
  "mediaType": "text/html",
  "source": {
    "content": "This is a post in the /c/tenforward community",
    "mediaType": "text/markdown"
  },
  "attachment": [
    {
      "type": "Link",
      "href": "https://enterprise.lemmy.ml/pictrs/image/eOtYb9iEiB.png"
    }
  ],
  "image": {
    "type": "Image",
    "url": "https://enterprise.lemmy.ml/pictrs/image/eOtYb9iEiB.png"
  },
  "sensitive": false,
  "commentsEnabled": true,
  "stickied": true,
  "language": {
    "identifier": "fr",
    "name": "Français"
  },
  "published": "2021-02-26T12:35:34.292626+00:00"
}
Field NameDescription
attributedToID of the user which created this post
toID of the community where it was posted to
nameTitle of the post (mandatory)
contentBody of the post
attachmentA single website or image link
imageThumbnail for url, only present if it is an image link
commentsEnabledFalse indicates that the post is locked, and no comments can be added
sensitiveTrue marks the post as NSFW, blurs the thumbnail and hides it from users with NSFW settign disabled
stickiedTrue means that it is shown on top of the community
publishedDatetime when the post was created
updatedDatetime when the post was edited (not present if it was never edited)

Comment

A reply to a post, or reply to another comment. Contains only text (including references to other users or communities). Lemmy displays comments in a tree structure.

{
  "id": "https://enterprise.lemmy.ml/comment/38741",
  "type": "Note",
  "attributedTo": "https://enterprise.lemmy.ml/u/picard",
  "to": ["https://www.w3.org/ns/activitystreams#Public"],
  "cc": [
    "https://enterprise.lemmy.ml/c/tenforward",
    "https://enterprise.lemmy.ml/u/picard"
  ],
  "audience": "https://enterprise.lemmy.ml/c/tenforward",
  "inReplyTo": "https://enterprise.lemmy.ml/post/55143",
  "content": "<p>first comment!</p>\n",
  "mediaType": "text/html",
  "source": {
    "content": "first comment!",
    "mediaType": "text/markdown"
  },
  "tag": [
    {
      "href": "https://enterprise.lemmy.ml/u/picard",
      "type": "Mention",
      "name": "@picard@enterprise.lemmy.ml"
    }
  ],
  "distinguished": false,
  "language": {
    "identifier": "fr",
    "name": "Français"
  },
  "published": "2021-03-01T13:42:43.966208+00:00",
  "updated": "2021-03-01T13:43:03.955787+00:00"
}
Field NameDescription
attributedToID of the user who created the comment
toCommunity where the comment was made
contentThe comment text
inReplyToID of the parent object. In case of a top-level comment this is the post ID, in case of a nested comment it is the parent comment ID.
publishedDatetime when the comment was created
updatedDatetime when the comment was edited (not present if it was never edited)

Private Message

A direct message from one user to another. Can not include additional users. Threading is not implemented yet, so the inReplyTo field is missing.

{
  "id": "https://enterprise.lemmy.ml/private_message/1621",
  "type": "ChatMessage",
  "attributedTo": "https://enterprise.lemmy.ml/u/picard",
  "to": [
    "https://queer.hacktivis.me/users/lanodan"
  ],
  "content": "<p>Hello hello, testing</p>\n",
  "mediaType": "text/html",
  "source": {
    "content": "Hello hello, testing",
    "mediaType": "text/markdown"
  },
  "published": "2021-10-21T10:13:14.597721+00:00"
}
Field NameDescription
attributedToID of the user who created this private message
toID of the recipient
contentThe text of the private message
publishedDatetime when the message was created
updatedDatetime when the message was edited (not present if it was never edited)

Collections

Community Outbox

{
  "type":"OrderedCollection",
  "id":"https://ds9.lemmy.ml/c/testcom/outbox",
  "totalItems":2,
  "orderedItems":[
    {
      "actor":"https://ds9.lemmy.ml/c/testcom",
      "to":[
        "https://www.w3.org/ns/activitystreams#Public"
      ],
      "object":{
        "actor":"https://ds9.lemmy.ml/u/nutomic",
        "to":[
          "https://www.w3.org/ns/activitystreams#Public"
        ],
        "cc":[
          "https://ds9.lemmy.ml/c/testcom"
        ],
        "type":"Create",
        "id":"http://ds9.lemmy.ml/activities/create/eee6a57a-622f-464d-b560-73ae1fcd3ddf",
        "object":{
          "type":"Page",
          "id":"https://ds9.lemmy.ml/post/2328",
          "attributedTo":"https://ds9.lemmy.ml/u/nutomic",
          "to":[
            "https://ds9.lemmy.ml/c/testcom",
            "https://www.w3.org/ns/activitystreams#Public"
          ],
          "name":"another outbox test",
          "mediaType":"text/html",
          "commentsEnabled":true,
          "sensitive":false,
          "stickied":false,
          "published":"2021-11-18T17:19:45.895163+00:00"
        }
      },
      "cc":[
        "https://ds9.lemmy.ml/c/testcom/followers"
      ],
      "type":"Announce",
      "id":"https://ds9.lemmy.ml/activities/announce/b204fe9f-b13d-4af2-9d22-239ac2d892e6"
    },
    {
      "actor":"https://ds9.lemmy.ml/c/testcom",
      "to":[
        "https://www.w3.org/ns/activitystreams#Public"
      ],
      "object":{
        "actor":"https://ds9.lemmy.ml/u/nutomic",
        "to":[
          "https://www.w3.org/ns/activitystreams#Public"
        ],
        "cc":[
          "https://ds9.lemmy.ml/c/testcom"
        ],
        "type":"Create",
        "id":"http://ds9.lemmy.ml/activities/create/eee6a57a-622f-464d-b560-73ae1fcd3ddf",
        "object":{
          "type":"Page",
          "id":"https://ds9.lemmy.ml/post/2327",
          "attributedTo":"https://ds9.lemmy.ml/u/nutomic",
          "to":[
            "https://ds9.lemmy.ml/c/testcom",
            "https://www.w3.org/ns/activitystreams#Public"
          ],
          "name":"outbox test",
          "mediaType":"text/html",
          "commentsEnabled":true,
          "sensitive":false,
          "stickied":false,
          "published":"2021-11-18T17:19:05.763109+00:00"
        }
      },
      "cc":[
        "https://ds9.lemmy.ml/c/testcom/followers"
      ],
      "type":"Announce",
      "id":"https://ds9.lemmy.ml/activities/announce/c6c960ce-c8d8-4231-925e-3ba367468f18"
    }
  ]
}

The outbox only contains Create/Post activities for now.

Community Followers

{
  "id": "http://enterprise.lemmy.ml/c/main/followers",
  "type": "Collection",
  "totalItems": 3,
  "items": []
}

The followers collection is only used to expose the number of followers. Actor IDs are not included, to protect user privacy.

Community Moderators

List of moderators who can perform actions like removing posts or banning users.

{
  "type": "OrderedCollection",
  "id": "https://enterprise.lemmy.ml/c/tenforward/moderators",
  "orderedItems": [
    "https://enterprise.lemmy.ml/u/picard"
  ]
}

List of posts which are stickied in the community.

{
  "type": "OrderedCollection",
  "id": "https://ds9.lemmy.ml/c/main/featured",
  "totalItems": 2,
  "orderedItems": [
    {
      "type": "Page",
      "id": "https://ds9.lemmy.ml/post/2",
      "attributedTo": "https://ds9.lemmy.ml/u/lemmy_alpha",
      "to": [
        "https://ds9.lemmy.ml/c/main",
        "https://www.w3.org/ns/activitystreams#Public"
      ],
      "name": "test 2",
      "cc": [],
      "mediaType": "text/html",
      "attachment": [],
      "commentsEnabled": true,
      "sensitive": false,
      "stickied": true,
      "published": "2023-02-06T06:42:41.939437+00:00",
      "language": {
        "identifier": "de",
        "name": "Deutsch"
      },
      "audience": "https://ds9.lemmy.ml/c/main"
    },
    {
      "type": "Page",
      "id": "https://ds9.lemmy.ml/post/1",
      "attributedTo": "https://ds9.lemmy.ml/u/lemmy_alpha",
      "to": [
        "https://ds9.lemmy.ml/c/main",
        "https://www.w3.org/ns/activitystreams#Public"
      ],
      "name": "test 1",
      "cc": [],
      "mediaType": "text/html",
      "attachment": [],
      "commentsEnabled": true,
      "sensitive": false,
      "stickied": true,
      "published": "2023-02-06T06:42:37.119567+00:00",
      "language": {
        "identifier": "de",
        "name": "Deutsch"
      },
      "audience": "https://ds9.lemmy.ml/c/main"
    }
  ]
}

User Outbox

Only contains totalItems count, but no actual items for privacy reasons.

{
  "type": "OrderedCollection",
  "id": "http://ds9.lemmy.ml/u/lemmy_alpha/outbox",
  "orderedItems": [],
  "totalItems": 0
}

Activities

User to Community

Follow

Each Community page has a "Follow" button. Clicking this triggers a Follow activity to be sent from the user to the Community inbox. The Community will automatically respond with an Accept/Follow activity to the user inbox. It will also add the user to its list of followers, and deliver any activities about Posts/Comments in the Community to the user.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "to": ["http://enterprise.lemmy.ml/c/main"],
  "object": "http://enterprise.lemmy.ml/c/main",
  "type": "Follow",
  "id": "http://ds9.lemmy.ml/activities/follow/6abcd50b-b8ca-4952-86b0-a6dd8cc12866"
}

Unfollow

After following a Community, the "Follow" button is replaced by "Unfollow". Clicking this sends an Undo/Follow activity to the Community inbox. The Community removes the User from its followers list and doesn't send any activities to it anymore.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "to": ["http://enterprise.lemmy.ml/c/main"],
  "object": {
    "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
    "to": ["http://enterprise.lemmy.ml/c/main"],
    "object": "http://enterprise.lemmy.ml/c/main",
    "type": "Follow",
    "id": "http://ds9.lemmy.ml/activities/follow/dc2f1bc5-f3a0-4daa-a46b-428cbfbd023c"
  },
  "type": "Undo",
  "id": "http://ds9.lemmy.ml/activities/undo/dd83c482-8ebd-4b6c-9008-c8373bd1a86a"
}

Create or Update Post

When a user creates a new post, it is sent to the respective community as Create/Page. Editing a previously created post sends an almost identical activity, except the type being Update.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": {
    "type": "Page",
    "id": "http://ds9.lemmy.ml/post/1",
    "attributedTo": "http://ds9.lemmy.ml/u/lemmy_alpha",
    "to": [
      "http://enterprise.lemmy.ml/c/main",
      "https://www.w3.org/ns/activitystreams#Public"
    ],
    "audience": "https://enterprise.lemmy.ml/c/main",
    "name": "test post",
    "content": "<p>test body</p>\n",
    "mediaType": "text/html",
    "source": {
      "content": "test body",
      "mediaType": "text/markdown"
    },
    "attachment": [
      {
        "type": "Link",
        "href": "https://lemmy.ml/pictrs/image/xl8W7FZfk9.jpg"
      }
    ],
    "commentsEnabled": true,
    "sensitive": false,
    "stickied": false,
    "language": {
      "identifier": "ko",
      "name": "한국어"
    },
    "published": "2021-10-29T15:10:51.557399+00:00"
  },
  "cc": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "audience": "https://enterprise.lemmy.ml/c/main",
  "type": "Create",
  "id": "http://ds9.lemmy.ml/activities/create/eee6a57a-622f-464d-b560-73ae1fcd3ddf"
}

Create or Update Comment

A reply to a post, or to another comment as Create/Note. Can contain mentions of other users. Editing a previously created post sends an almost identical activity, except the type being Update.

The origin instance also scans the Comment for any User mentions, and sends the Create/Note to those Users as well.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": {
    "type": "Note",
    "id": "http://ds9.lemmy.ml/comment/1",
    "attributedTo": "http://ds9.lemmy.ml/u/lemmy_alpha",
    "to": [
      "https://www.w3.org/ns/activitystreams#Public"
    ],
    "cc": [
      "http://enterprise.lemmy.ml/c/main",
      "http://ds9.lemmy.ml/u/lemmy_alpha"
    ],
    "audience": "http://ds9.lemmy.ml/u/lemmy_alpha",
    "content": "hello",
    "mediaType": "text/html",
    "source": {
      "content": "hello",
      "mediaType": "text/markdown"
    },
    "inReplyTo": "http://ds9.lemmy.ml/post/1",
    "published": "2021-11-01T11:45:49.794920+00:00"
  },
  "cc": [
    "http://enterprise.lemmy.ml/c/main",
    "http://ds9.lemmy.ml/u/lemmy_alpha"
  ],
  "audience": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "tag": [
    {
      "href": "http://ds9.lemmy.ml/u/lemmy_alpha",
      "type": "Mention",
      "name": "@lemmy_alpha@ds9.lemmy.ml"
    }
  ],
  "type": "Create",
  "id": "http://ds9.lemmy.ml/activities/create/1e77d67c-44ac-45ed-bf2a-460e21f60236"
}

Like Post or Comment

An upvote for a post or comment.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "object": "http://ds9.lemmy.ml/comment/1",
  "audience": "https://enterprise.lemmy.ml/c/tenforward",
  "type": "Like",
  "id": "http://ds9.lemmy.ml/activities/like/fd61d070-7382-46a9-b2b7-6bb253732877"
}

Dislike Post or Comment

A downvote for a post or comment.

{
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "object": "http://ds9.lemmy.ml/post/1",
  "audience": "https://enterprise.lemmy.ml/c/tenforward",
  "type": "Dislike",
  "id": "http://enterprise.lemmy.ml/activities/dislike/64d40d40-a829-43a5-8247-1fb595b3ca1c"
}

Undo Like or Dislike Post or Comment

Revert a vote that was previously done by the same user.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "object": {
    "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
    "object": "http://ds9.lemmy.ml/comment/1",
    "audience": "https://enterprise.lemmy.ml/c/tenforward",
    "type": "Like",
    "id": "http://ds9.lemmy.ml/activities/like/efcf7ae2-dfcc-4ff4-9ce4-6adf251ff004"
  },
  "audience": "https://enterprise.lemmy.ml/c/tenforward",
  "type": "Undo",
  "id": "http://ds9.lemmy.ml/activities/undo/3518565c-24a7-4d9e-8e0a-f7a2f45ac618"
}

Delete Post or Comment

Mods can remove Posts and Comments from their Communities. Admins can remove any Posts or Comments on the entire site. Communities can also be removed by admins. The item is then hidden from all users.

Removals are sent to all followers of the Community, so that they also take effect there. The exception is if an admin removes an item from a Community which is hosted on a different instance. In this case, the removal only takes effect locally.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": "http://ds9.lemmy.ml/post/1",
  "cc": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "audience": "http://enterprise.lemmy.ml/u/main",
  "type": "Delete",
  "id": "http://ds9.lemmy.ml/activities/delete/f2abee48-c7bb-41d5-9e27-8775ff32db12"
}

Undo Delete

Post or comment deletions can be reverted by the same user.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": {
    "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
    "to": [
      "https://www.w3.org/ns/activitystreams#Public"
    ],
    "object": "http://ds9.lemmy.ml/post/1",
    "cc": [
      "http://enterprise.lemmy.ml/c/main"
    ],
    "audience": "http://enterprise.lemmy.ml/u/main",
    "type": "Delete",
    "id": "http://ds9.lemmy.ml/activities/delete/b13cca96-7737-41e1-9769-8fbf972b3509"
  },
  "cc": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "audience": "http://enterprise.lemmy.ml/u/main",
  "type": "Undo",
  "id": "http://ds9.lemmy.ml/activities/undo/5e939cfb-b8a1-4de8-950f-9d684e9162b9"
}

Report Post, comment or private message

Reports content for rule violation, so that mods/admins can review it.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "to": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "audience": "http://enterprise.lemmy.ml/u/main",
  "object": "http://enterprise.lemmy.ml/post/7",
  "summary": "report this post",
  "type": "Flag",
  "id": "http://ds9.lemmy.ml/activities/flag/98b0933f-5e45-4a95-a15f-e0dc86361ba4"
}

Delete User

Sent when a user deletes his own account.

{
  "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "type": "Delete",
  "id": "http://ds9.lemmy.ml/activities/delete/f2abee48-c7bb-41d5-9e27-8775ff32db12"
}

Community to User

Accept Follow

Automatically sent by the community in response to a Follow. At the same time, the community adds this user to its followers list.

{
  "actor": "http://enterprise.lemmy.ml/c/main",
  "to": ["http://ds9.lemmy.ml/u/lemmy_alpha"],
  "object": {
    "actor": "http://ds9.lemmy.ml/u/lemmy_alpha",
    "to": ["http://enterprise.lemmy.ml/c/main"],
    "object": "http://enterprise.lemmy.ml/c/main",
    "type": "Follow",
    "id": "http://ds9.lemmy.ml/activities/follow/6abcd50b-b8ca-4952-86b0-a6dd8cc12866"
  },
  "type": "Accept",
  "id": "http://enterprise.lemmy.ml/activities/accept/75f080cc-3d45-4654-8186-8f3bb853fa27"
}

Announce

If the Community receives any Post or Comment related activity (Create, Update, Like, Dislike, Remove, Delete, Undo etc.), it will forward this to its followers. For this, an Announce is created with the Community as actor, and the received activity as object. This is sent to all followers, so they get updated in real time.

{
  "actor": "http://enterprise.lemmy.ml/c/main",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": {
    "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
    "to": [
      "https://www.w3.org/ns/activitystreams#Public"
    ],
    "object": {
      "type": "Page",
      "id": "http://enterprise.lemmy.ml/post/7",
      "attributedTo": "http://enterprise.lemmy.ml/u/lemmy_beta",
      "to": [
        "http://enterprise.lemmy.ml/c/main",
        "https://www.w3.org/ns/activitystreams#Public"
      ],
      "name": "post 4",
      "mediaType": "text/html",
      "commentsEnabled": true,
      "sensitive": false,
      "stickied": false,
      "published": "2021-11-01T12:11:22.871846+00:00"
    },
    "cc": [
      "http://enterprise.lemmy.ml/c/main"
    ],
    "type": "Create",
    "id": "http://enterprise.lemmy.ml/activities/create/2807c9ec-3ad8-4859-a9e0-28b59b6e499f"
  },
  "cc": [
    "http://enterprise.lemmy.ml/c/main/followers"
  ],
  "type": "Announce",
  "id": "http://enterprise.lemmy.ml/activities/announce/8030b171-803a-4108-94b1-342688f375cf"
}

Moderation

These actions can only be done by instance admins or community moderators. They are sent to the community and announced by it. See for a general overview how moderation works in Lemmy. Communities can only be created on the same instance where a user is registered. After that, mods from other instances can be added with Add/User activity.

Remove Post or Comment

Removes a post or comment. The difference to delete is that remove activities have a summary field, which contains the reason for removal, as provided by the mod/admin.

{
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": "http://ds9.lemmy.ml/comment/1",
  "cc": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "audience": "http://enterprise.lemmy.ml/u/main",
  "type": "Delete",
  "summary": "bad comment",
  "id": "http://enterprise.lemmy.ml/activities/delete/42ca1a79-f99e-4518-a2ca-ba2df221eb5e"
}

Block User

Blocks a user so he can't participate anymore. The scope is determined by the target field: either a community, or a whole instance. The removeData field can optionally be set to indicate that all previous posts of the user should be deleted.

{
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "cc": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "audience": "http://enterprise.lemmy.ml/u/main",
  "target": "http://enterprise.lemmy.ml/c/main",
  "type": "Block",
  "removeData": true,
  "summary": "spam post",
  "expires": "2021-11-01T12:23:50.151874+00:00",
  "id": "http://enterprise.lemmy.ml/activities/block/5d42fffb-0903-4625-86d4-0b39bb344fc2"
}

Lock post

Posts can be locked so that no new comments can be created.

{
      "id": "http://lemmy-alpha:8541/activities/lock/cb48761d-9e8c-42ce-aacb-b4bbe6408db2",
      "actor": "http://lemmy-alpha:8541/u/lemmy_alpha",
      "to": [
            "https://www.w3.org/ns/activitystreams#Public"
      ],
      "object": "http://lemmy-alpha:8541/post/2",
      "cc": [
            "http://lemmy-alpha:8541/c/main"
      ],
      "type": "Lock",
      "audience": "http://lemmy-alpha:8541/c/main"
}

Undo mod actions

All previously listed mod actions can be reverted by wrapping the original activity in Undo. Note that Lemmy regenerates the inner activity with a new ID.

{
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": {
    "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
    "to": [
      "https://www.w3.org/ns/activitystreams#Public"
    ],
    "object": "http://ds9.lemmy.ml/comment/1",
    "cc": [
      "http://enterprise.lemmy.ml/c/main"
    ],
    "audience": "http://enterprise.lemmy.ml/u/main",
    "type": "Delete",
    "summary": "bad comment",
    "id": "http://enterprise.lemmy.ml/activities/delete/2598435c-87a3-49cd-81f3-a44b03b7af9d"
  },
  "cc": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "audience": "http://enterprise.lemmy.ml/u/main",
  "type": "Undo",
  "id": "http://enterprise.lemmy.ml/activities/undo/a850cf21-3866-4b3a-b80b-56aa00997fee"
}
{
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": {
    "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
    "to": [
      "https://www.w3.org/ns/activitystreams#Public"
    ],
    "object": "http://ds9.lemmy.ml/u/lemmy_alpha",
    "cc": [
      "http://enterprise.lemmy.ml/c/main"
    ],
    "audience": "http://enterprise.lemmy.ml/u/main",
    "target": "http://enterprise.lemmy.ml/c/main",
    "type": "Block",
    "removeData": true,
    "summary": "spam post",
    "expires": "2021-11-01T12:23:50.151874+00:00",
    "id": "http://enterprise.lemmy.ml/activities/block/726f43ab-bd0e-4ab3-89c8-627e976f553c"
  },
  "cc": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "audience": "http://enterprise.lemmy.ml/u/main",
  "type": "Undo",
  "id": "http://enterprise.lemmy.ml/activities/undo/06a20ffb-3e32-42fb-8f4c-674b36d7c557"
}

Add or remove featured post

Posts can be pinned so that they are always shown on top of the community. This is federated with the Community featured posts collection.

{
  "cc": [
    "https://ds9.lemmy.ml/c/main"
  ],
  "id": "https://ds9.lemmy.ml/activities/add/47d911f5-52c5-4659-b2fd-0e58c451a427",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "type": "Add",
  "actor": "https://ds9.lemmy.ml/u/lemmy_alpha",
  "object": "https://ds9.lemmy.ml/post/2",
  "target": "https://ds9.lemmy.ml/c/main/featured",
  "audience": "https://ds9.lemmy.ml/c/main"
}
{
  "cc": [
    "https://ds9.lemmy.ml/c/main"
  ],
  "id": "https://ds9.lemmy.ml/activities/add/47d911f5-52c5-4659-b2fd-0e58c451a427",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "type": "Remove",
  "actor": "https://ds9.lemmy.ml/u/lemmy_alpha",
  "object": "https://ds9.lemmy.ml/post/2",
  "target": "https://ds9.lemmy.ml/c/main/featured",
  "audience": "https://ds9.lemmy.ml/c/main"
}

Add or remove mod

Add a new mod to the community. Has to be sent by an existing community mod, or an admin of the community's instance.

{
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "target": "http://enterprise.lemmy.ml/c/main/moderators",
  "cc": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "audience": "http://enterprise.lemmy.ml/u/main",
  "type": "Add",
  "id": "http://enterprise.lemmy.ml/activities/add/ec069147-77c3-447f-88c8-0ef1df10403f"
}

An existing mod can be removed in the same way.

{
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "object": "http://ds9.lemmy.ml/u/lemmy_alpha",
  "cc": [
    "http://enterprise.lemmy.ml/c/main"
  ],
  "type": "Remove",
  "target": "http://enterprise.lemmy.ml/c/main/moderators",
  "audience": "http://enterprise.lemmy.ml/u/main",
  "id": "http://enterprise.lemmy.ml/activities/remove/aab114f8-cfbd-4935-a5b7-e1a64603650d"
}

User to User

Follow a user

Users from other platforms can follow Lemmy users and receive all of their posts to the inbox. Note that users who are registered on Lemmy can only follow groups, not other users.

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://mycrowd.ca/schemas/litepub-0.1.jsonld",
    {
      "@language": "und"
    }
  ],
  "actor": "https://mycrowd.ca/users/kinetix",
  "cc": [],
  "id": "https://mycrowd.ca/activities/dab6a4d3-0db0-41ee-8aab-7bfa4929b4fd",
  "object": "https://lemmy.ca/u/kinetix",
  "state": "pending",
  "to": [
    "https://lemmy.ca/u/kinetix"
  ],
  "type": "Follow"
}

Create or Update Private message

User profiles have a "Send Message" button, which opens a dialog permitting to send a private message to this user. It is sent as a Create/ChatMessage to the user inbox. Private messages can only be directed at a single User. They can also be edited with Update/ChatMessage.

{
  "id": "http://enterprise.lemmy.ml/activities/create/987d05fa-f637-46d7-85be-13d112bc269f",
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "to": [
    "http://ds9.lemmy.ml/u/lemmy_alpha"
  ],
  "object": {
    "type": "ChatMessage",
    "id": "http://enterprise.lemmy.ml/private_message/1",
    "attributedTo": "http://enterprise.lemmy.ml/u/lemmy_beta",
    "to": [
      "http://ds9.lemmy.ml/u/lemmy_alpha"
    ],
    "content": "hello",
    "mediaType": "text/html",
    "source": {
      "content": "hello",
      "mediaType": "text/markdown"
    },
    "published": "2021-10-29T15:31:56.058289+00:00"
  },
  "type": "Create"
}

Delete Private Message

Deletes a previous private message.

{
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "to": [
    "http://enterprise.lemmy.ml/u/lemmy_beta"
  ],
  "object": "http://enterprise.lemmy.ml/private_message/1",
  "type": "Delete",
  "id": "http://enterprise.lemmy.ml/activities/delete/041d9858-5eef-4ad9-84ae-7455b4d87ed9"
}

Undo Delete Private Message

Restores a previously deleted private message. The object is regenerated from scratch, as such the activity ID and other fields are different.

{
  "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
  "to": [
    "http://ds9.lemmy.ml/u/lemmy_alpha"
  ],
  "object": {
    "actor": "http://enterprise.lemmy.ml/u/lemmy_beta",
    "to": [
      "http://enterprise.lemmy.ml/u/lemmy_beta"
    ],
    "object": "http://enterprise.lemmy.ml/private_message/1",
    "type": "Delete",
    "id": "http://enterprise.lemmy.ml/activities/delete/616c41be-04ed-4bd4-b865-30712186b122"
  },
  "type": "Undo",
  "id": "http://enterprise.lemmy.ml/activities/undo/35e5b337-014c-4bbe-8d63-6fac96f51409"
}

Resources / Libraries

Rust

Typescript

Trees

Sorting

SQL

ActivityPub Resources

Official Documents

Explanations

Examples and Libraries

Code of Conduct

  • We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
  • Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe and welcoming environment for all.
  • Please be kind and courteous. There’s no need to be mean or rude.
  • Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
  • Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
  • We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term “harassment” as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behavior that excludes people in socially marginalized groups.
  • Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the Lemmy moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back.
  • Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.

Message the Moderation Team on Mastodon

Email The Moderation Team

Moderation

These are the policies for upholding our community’s standards of conduct. If you feel that a thread needs moderation, please contact the Lemmy moderation team .

  1. Remarks that violate the Lemmy standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
  2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
  3. Moderators will first respond to such remarks with a warning, at the same time the offending content will likely be removed whenever possible.
  4. If the warning is unheeded, the user will be “kicked,” i.e., kicked out of the communication channel to cool off.
  5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
  6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
  7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, in private. Complaints about bans in-channel are not allowed.
  8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.

In the Lemmy community we strive to go the extra step to look out for each other. Don’t just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they’re off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.

And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could’ve communicated better — remember that it’s your responsibility to make others comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.

The enforcement policies listed above apply to all official Lemmy venues; including git repositories under github.com/LemmyNet and git.join-lemmy.org/LemmyNet, the Matrix chat; lemmy.ml and other instances under that domain. For other projects adopting the Lemmy Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.

Adapted from the Rust Code of Conduct, which is based on the Node.js Policy on Trolling as well as the Contributor Covenant v1.3.0.