How to Self-Host Lemmy with Docker Compose

A Federated Reddit You Actually Control

Lemmy is a link aggregator and discussion platform for the fediverse. Think Reddit, but decentralized — your Lemmy instance federates with other Lemmy instances and the broader ActivityPub network. Users on any instance can subscribe to communities on any other instance, vote on posts, and comment across server boundaries. Official site

Born from the 2023 Reddit API controversy that killed third-party apps, Lemmy saw explosive growth and has matured significantly since. The v0.19.x series is stable and feature-rich, with v1.0 in alpha testing.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose v2+ installed (guide)
  • 2 GB RAM minimum
  • 10 GB of free disk space
  • A domain name with DNS configured
  • SMTP credentials (recommended for email notifications)
RequirementMinimumRecommended
CPU2 cores4 cores
RAM1 GB2 GB
Disk10 GB20 GB+
EmailOptionalSMTP for notifications

Docker Compose Configuration

Lemmy has four services: the backend API, the web frontend, PostgreSQL, and pictrs (image hosting).

services:
  lemmy:
    image: dessalines/lemmy:0.19.15
    restart: unless-stopped
    volumes:
      - ./lemmy.hjson:/config/config.hjson:ro
    depends_on:
      postgres:
        condition: service_healthy
      pictrs:
        condition: service_started
    networks:
      - lemmy

  lemmy-ui:
    image: dessalines/lemmy-ui:0.19.15
    restart: unless-stopped
    environment:
      LEMMY_UI_LEMMY_INTERNAL_HOST: lemmy:8536
      LEMMY_UI_LEMMY_EXTERNAL_HOST: lemmy.example.com
      LEMMY_UI_HTTPS: "true"
    depends_on:
      - lemmy
    networks:
      - lemmy

  pictrs:
    image: asonix/pictrs:0.5.27
    restart: unless-stopped
    user: 991:991
    volumes:
      - pictrs-data:/mnt/sled-repo
      - pictrs-data:/mnt/files
    environment:
      PICTRS__MEDIA__VIDEO_CODEC: vp9
      PICTRS__MEDIA__GIF__MAX_WIDTH: 256
      PICTRS__MEDIA__GIF__MAX_HEIGHT: 256
      PICTRS__MEDIA__GIF__MAX_AREA: 65536
      PICTRS__MEDIA__GIF__MAX_FRAME_COUNT: 400
    networks:
      - lemmy

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    shm_size: 256mb
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: lemmy
      POSTGRES_USER: lemmy
      POSTGRES_PASSWORD: change_this_strong_password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U lemmy"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - lemmy

  proxy:
    image: nginx:1-alpine
    restart: unless-stopped
    ports:
      - "127.0.0.1:8536:8536"
    volumes:
      - ./nginx_internal.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - lemmy
      - lemmy-ui
      - pictrs
    networks:
      - lemmy

networks:
  lemmy:

volumes:
  postgres-data:
  pictrs-data:

Lemmy Configuration (lemmy.hjson)

Create lemmy.hjson alongside your docker-compose.yml:

{
  # The domain of your Lemmy instance (CANNOT be changed after first run)
  hostname: "lemmy.example.com"

  # Bind address for the API server
  bind: "0.0.0.0"
  port: 8536

  # Set to true for HTTPS (production)
  tls_enabled: true

  # Database connection
  database: {
    uri: "postgres://lemmy:change_this_strong_password@postgres/lemmy"
  }

  # Image hosting service
  pictrs: {
    url: "http://pictrs:8080/"
    api_key: "generate_a_random_api_key_here"
  }

  # Email (optional but recommended)
  email: {
    smtp_server: "smtp.example.com:587"
    smtp_login: "your_smtp_user"
    smtp_password: "your_smtp_password"
    smtp_from_address: "[email protected]"
    tls_type: "starttls"
  }

  # Instance settings
  setup: {
    admin_username: "admin"
    admin_password: "change_this_admin_password"
    site_name: "My Lemmy Instance"
  }
}

Nginx Internal Configuration (nginx_internal.conf)

Create nginx_internal.conf — this routes traffic between the API and frontend:

worker_processes auto;

events {
    worker_connections 1024;
}

http {
    upstream lemmy {
        server "lemmy:8536";
    }
    upstream lemmy-ui {
        server "lemmy-ui:1234";
    }

    server {
        listen 8536;
        server_name localhost;

        # API and federation endpoints
        location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known) {
            proxy_pass http://lemmy;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        # Frontend
        location / {
            set $proxpass "http://lemmy-ui";

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

            proxy_pass $proxpass;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

Start everything:

docker compose up -d

Initial Setup

  1. Navigate to https://lemmy.example.com

  2. Log in with the admin credentials from lemmy.hjson (admin / your password)

  3. Go to Admin Settings to configure:

    • Site name, description, sidebar content
    • Registration mode (open, application-required, closed)
    • Federation settings (allowed/blocked instances)
    • Content policies (NSFW, slur filter)
  4. Create your first community at /create_community

Configuration

Key Settings in lemmy.hjson

SettingPurposeNotes
hostnameInstance domainImmutable after first run
database.uriPostgreSQL connectionInclude password
pictrs.urlImage hosting serviceInternal URL
emailSMTP configurationRequired for password resets
setup.admin_usernameFirst admin accountOnly used on initial setup
federation.enabledEnable ActivityPubtrue by default
federation.allowed_instancesAllowlist (empty = all)Leave empty for open federation
federation.blocked_instancesBlocklistBlock specific instances

Admin Panel Settings

Access via /admin:

  • Registration: Open, require application, or closed
  • Content: Enable/disable NSFW, downvotes, bot accounts
  • Rate limiting: Post, comment, search, and register rate limits
  • Taglines: Rotating taglines on the homepage
  • Custom CSS/JS: Style your instance

Reverse Proxy

The internal nginx proxy listens on port 8536. Place your external reverse proxy in front of it.

Caddy:

lemmy.example.com {
    reverse_proxy localhost:8536
}

See our Reverse Proxy Setup guide for Nginx Proxy Manager and Traefik examples.

Backup

# Database backup
docker compose exec postgres pg_dump -U lemmy lemmy > lemmy_backup_$(date +%F).sql

# Image data backup
docker run --rm -v lemmy_pictrs-data:/data -v $(pwd):/backup \
  alpine tar czf /backup/pictrs_backup_$(date +%F).tar.gz -C /data .

Also back up lemmy.hjson and nginx_internal.conf. See our Backup Strategy guide.

Troubleshooting

Federation Not Working

Symptom: Can’t find communities on other instances. Fix: Check that your instance is reachable at https://lemmy.example.com/.well-known/nodeinfo. Verify the internal nginx config routes /api and /.well-known to the backend, not the frontend. Check logs: docker compose logs lemmy | grep -i error.

502 Bad Gateway

Symptom: Nginx returns 502 errors. Fix: The backend hasn’t started yet or crashed. Check docker compose logs lemmy for errors. Common cause: wrong database password in lemmy.hjson — it must match POSTGRES_PASSWORD in the Compose file.

Images Not Loading

Symptom: Uploaded images show broken image icons. Fix: Check pictrs is running: docker compose logs pictrs. Verify the pictrs.api_key in lemmy.hjson matches if you set one. Check volume permissions — pictrs runs as UID 991.

Search Returns No Results

Symptom: Searching for remote communities or users returns nothing. Fix: Lemmy uses WebFinger to resolve remote resources. Use the full URL format: [email protected] for communities, @[email protected] for users. The first search triggers a federation lookup — wait a moment and retry.

High Memory Usage

Symptom: Server running out of RAM. Fix: PostgreSQL is usually the culprit. Reduce shared_buffers and work_mem in PostgreSQL config. Add shm_size: 256mb to the postgres service. Consider increasing swap space on small servers.

Resource Requirements

ResourceSmall Instance (<100 users)Medium Instance (100-1000 users)
RAM1-2 GB3-4 GB
CPU2 cores4 cores
Disk10 GB30-50 GB
Bandwidth10 GB/month50+ GB/month

Lemmy is more lightweight than Mastodon but heavier than GoToSocial. The five containers (backend, frontend, postgres, pictrs, nginx) add up. Plan for pictrs storage growth if your users post images.

Verdict

Lemmy is the best self-hosted Reddit alternative. The federation model means your community can interact with every other Lemmy instance and the broader fediverse. The moderation tools are solid, communities are well-organized, and the user experience is familiar to anyone who’s used Reddit.

Choose Lemmy if you want to build a link-aggregation community with upvotes, communities, and threaded comments. It’s Reddit, but you own it and it federates.

Look elsewhere if you want a traditional forum experience. Discourse is better for long-form discussions. If you want a microblogging platform, use Mastodon or GoToSocial instead.

FAQ

Can users on other Lemmy instances post in my communities?

Yes. That’s the core value proposition. Users on any federated Lemmy instance can subscribe to, post in, and comment on your communities. Votes also federate.

Is Lemmy compatible with Mastodon?

Partially. Mastodon users can follow Lemmy communities and see posts in their timeline. They can comment on posts (which appear as replies in Lemmy). However, the full Reddit-like experience (voting, creating posts) works best from a Lemmy client.

How do I moderate effectively across federation?

Instance-level moderation (admin) can block entire instances, IP ranges, and individual users. Community-level moderation (moderators) can remove posts, ban users from specific communities, and set content rules. Each community can have different moderators.

What clients are available?

Web frontend is the primary client. Mobile apps include Jerboa (official Android), Thunder, Voyager, and Boost for Lemmy. Most support multiple instances.

Can I import data from Reddit?

There’s no official import tool, but community-built tools can export your Reddit subscriptions and bookmarks. Content doesn’t migrate — you start fresh on Lemmy.

Comments