About Reddit, Lemmy and Self-Hosting It on Kubernetes

With all the backlash1 surrounding Reddit’s unpopular decision to restrict their API while effectively killing most of the 3rd party apps in the process, many started wondering whether Reddit should remain their “front page of the Internet” and maybe even started to explore alternatives.

Background

People who have been on the internet for a while might be currently experiencing a bad case of déjà vu. For those who weren’t around back then, Reddit’s biggest user influx has happened at the same time when the core users of Digg (a popular link aggregator of the 10s) started protesting some changes their platform of choice had recently introduced. 2 Fast forward a decade later, and here we are once again with a user base being unhappy with their platform. But unlike several years ago, now they don’t really have a 1:1 alternative they can go to. More on that later.

Back to Reddit: In spite of all the protests that have happened in the recent weeks, it looks like the new API policy is here to stay3 and we are stuck with the official Reddit apps for good. Unless of course you are on Android and are willing to patch your favorite 3rd party app with your own API key and keep using that. But that’s bad, m’kay?

Historical Examples

As mentioned earlier, when Digg started digging their own grave, Reddit was already widely regarded as the cool kid around the block, which made it the de facto target of many disappointed Digg users. But when #TwitterMigration4 came around many years later, things were already pretty different.

This time there were no clear alternatives. Instead, users were encouraged to join the Fediverse and try Mastodon. While Mastodon seemed like a perfect substitute for Twitter if you squinted hard enough, in reality they offered a vastly different user experience. Due to this discrepancy, #TwitterMigration really wasn’t quite the success many were hoping for. 5

Where to, then?

Now that Reddit seems to be pretty determined in executing their original plans, the question comes up again: Where to, then?

Unfortunately, there is no clear answer here. Without an easy-to-use, centralized platform (where leaders are a little less profit-oriented and maybe not so authoritarian in their decision making), we are once again stuck with what the Fediverse has to offer.

The good news is, things are a lot more polished now in many ways (thanks to Mastodon and the awesome community behind all the ActivityPub-based projects). The bad news is, user experience is still not great and now there are multiple competing platforms to choose from. While competition in general is a very healthy thing (be it competing corporations or technologies), the average Joe prefers being pointed to an easy-to-use platform which is very similar to what he is already used to. He just wants to install an app, log in, and keep enjoying tweets from his favorite celebrities and friends.

Unfortunately, this is definitely not what Lemmy, Kbin or other Fediverse-based alternatives offer today, but they are the next best thing. If you decide to try them, now’s the perfect time.

Lemmy

I admittedly didn’t spend a whole lot of effort comparing all the Reddit-alternatives out there, so I’ve just went with the one which had the largest user base that day, and it was Lemmy. If you are interested in learning more about it, I highly recommend visiting join-lemmy.org for details.

With the platform selected, one can opt to join an existing instance or they can go ahead and create their own. As a technologist myself, I like to get my hands dirty, so I’ve decided to roll my own instance. In case you prefer convenience, you are free to join mine. If you decide to do so, please mention this article in your application so that I know you’re not a robot: https://fost.hu/

In my home lab I run k3s with Traefik as the ingress. Even though there were already official docker images available at my disposal, the official documentation didn’t really cover any use cases other than installing Lemmy on bare metal or VM with Ansible or deploying with docker-compose. It was also silent about alternative reverse proxies, such as Traefik.

Fortunately these images seem to be well designed and easy to scale, so it was trivial to come up with a few kubernetes manifests to quickly get started.

Deployment to Kubernetes with Traefik

Some prerequisites are required before you can get started. These are the following:

  • Kubernetes cluster
  • Traefik
  • IngressRoute CRD for Traefik
  • A properly configured certificate resolver for Traefik
  • PostgreSQL instance
  • Dedicated PostgreSQL database
  • Dedicated PostgreSQL user who owns the database above

lemmy-secret.yaml

Here you can provide a database connection string containing the login password and also the SMTP password for your e-mail provider. I personally like to use Mailgun for smaller projects even though their free plan became severely limited recently.

apiVersion: v1
kind: Secret
metadata:
    name: lemmy
    namespace: default
type: Opaque
stringData:
    LEMMY_DATABASE_URL: postgres://lemmy:this-is-my-password@postgres:5432/lemmy
    LEMMY_SMTP_PASSWORD: smtp-password

lemmy-configmap.yaml

Many settings are dynamic, which means you can tweak them on the application frontend itself, but some supposed to be provided here. The list of available configuration options are available here.

kind: ConfigMap
apiVersion: v1
metadata:
  name: lemmy
  namespace: default
data:
  config.hjson: |
    {
      hostname: "example.com"
      email: {
        smtp_server: "smtp.example.com:587"
        smtp_from_address: "noreply@example.com"
        smtp_login: "lemmy@example.com"
        tls_type: "tls"
      }
    }    

lemmy-deployment.yaml

Not a lot is happening here; Key-value pairs from the Secret above are mounted as environmental variables here. The ConfigMap resource is mounted as a file.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: lemmy
spec:
  selector:
    matchLabels:
      app: lemmy
  template:
    metadata:
      labels:
        app: lemmy
    spec:
      containers:
        - name: lemmy
          image: dessalines/lemmy:0.18.1-rc.4
          ports:
            - containerPort: 8536
          env:
            - name: TZ
              value: Europe/Budapest
          envFrom:
            - secretRef:
                name: lemmy
          volumeMounts:
            - name: config
              mountPath: /config/config.hjson
              subPath: config.hjson
      volumes:
      - name: config
        configMap:
          name: lemmy
          items:
          - key: config.hjson
            path: config.hjson
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: lemmy-ui
spec:
  selector:
    matchLabels:
      app: lemmy-ui
  template:
    metadata:
      labels:
        app: lemmy-ui
    spec:
      containers:
        - name: lemmy-ui
          image: dessalines/lemmy-ui:0.18.1-rc.7
          ports:
            - containerPort: 1234
          env:
            - name: TZ
              value: Europe/Budapest
            - name: LEMMY_UI_LEMMY_INTERNAL_HOST
              value: lemmy:8536
            - name: LEMMY_UI_LEMMY_EXTERNAL_HOST
              value: example.com
            - name: LEMMY_UI_HTTPS
              value: "true"

lemmy-service.yaml

---
apiVersion: v1
kind: Service
metadata:
  name: lemmy
spec:
  ports:
  - name: http
    port: 8536
    targetPort: 8536
    protocol: TCP
  selector:
    app: lemmy
---
apiVersion: v1
kind: Service
metadata:
  name: lemmy-ui
spec:
  ports:
  - name: http
    port: 1234
    targetPort: 1234
    protocol: TCP
  selector:
    app: lemmy-ui

lemmy-ingressroute.yaml

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: lemmy
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`example.com`) && (PathPrefix(`/api`, `/pictrs`, `/feeds`, `/nodeinfo`, `/.well-known`) || Method(`POST`) || HeadersRegexp(`Accept`, `^[Aa]pplication/.*`))
      kind: Rule
      services:
        - name: lemmy
          port: 8536
    - match: Host(`example.com`)
      kind: Rule
      services:
        - name: lemmy-ui
          port: 1234
  tls:
    certResolver: myresolver

That’s it, really.

After you have applied these manifests to your cluster, you should be able to go to the ingress URL and create your admin user.

Once that’s done, you should probably check whether your e-mail setup is working and maybe double-check the settings in the admin section. Even if you choose to restrict new registrations, don’t forget to enable federation which is off by default.

Enjoy!

References


  1. Amadeo, R. (2023, June 5). Reddit’s plan to kill third-party apps sparks widespread protests. Ars Technica. https://arstechnica.com/gadgets/2023/06/reddits-plan-to-kill-third-party-apps-sparks-widespread-protests/ ↩︎

  2. MacManus, R. (2010, August 30). Digg User Rebellion Continues: Reddit Now Rules the Front Page. ReadWriteWeb. https://web.archive.org/web/20100831122556/http://www.readwriteweb.com/archives/digg_user_rebellion_reddit_on_front_page.php ↩︎

  3. Harding, S. (2023) Reddit API changes are imminent. here’s what’s happening to your favorite apps. Ars Technica. https://arstechnica.com/gadgets/2023/06/reddit-api-changes-are-imminent-heres-whats-happening-to-your-favorite-apps/ (Accessed: 02 July 2023). ↩︎

  4. Ilyushina, N. (2022, November 8). What is Mastodon, the ‘Twitter alternative’ people are flocking to? Here’s everything you need to know. The Conversation. https://theconversation.com/what-is-mastodon-the-twitter-alternative-people-are-flocking-to-heres-everything-you-need-to-know-194059 ↩︎

  5. Bayliss, M. (2023, June 29). Op-ed: Why the great #TwitterMigration didn’t quite pan out. Ars Technica. https://arstechnica.com/information-technology/2023/06/op-ed-why-the-great-twittermigration-didnt-quite-pan-out/ ↩︎