Deutsch
Loslegen
← Alle Vorlagen

Lemmy mit einem Klick auf Pethost deployen

Ein Link-Aggregator und Forum für das Fediverse

Was passiert

  1. Du meldest dich bei Pethost an oder legst ein Konto an, mit Passkey, GitHub oder Google.
  2. Noch keine Maschine? Du wählst einen Tarif, und wir bereiten eine für dich vor. Der Link wartet in deinem Browser, bis sie bereit ist.
  3. „Neues Projekt“ öffnet sich bei der App. Du füllst aus, was sie braucht, und klickst auf „Projekt erstellen“: Admin-Passwort.
  4. In ein, zwei Minuten läuft die App unter eigener Adresse mit HTTPS. Ihre Secrets werden zufällig für sie erzeugt, und ihre Daten sind im nächtlichen Backup.
  5. Sie ist ein Projekt wie jedes andere: compose.yaml, .env, Logs und ein Terminal findest du im Panel, und dein Agent kann sie ändern, zurückrollen oder wiederherstellen.

Erste Schritte

Melde dich als admin mit dem Passwort an, das du festgelegt hast; der erste Start dauert ein bis zwei Minuten. Neue Konten warten auf deine Bestätigung: „Registration Mode“ findest du unter „Admin Settings“. Das Passwort änderst du in den Einstellungen von Lemmy selbst: Das aus der .env wird nur einmal gelesen. Die Adresse ist der Name der Instanz im Fediverse, behalt sie also bei.

Was läuft

Die Vorlage ist diese compose.yaml und die Variablen, die sie in die .env des Projekts schreibt. Pethost führt die Datei so aus, wie sie geschrieben ist.

services:
  # Lemmy's own front door: a fediverse server asks for a page as ActivityPub
  # JSON, and those requests, the API's and every non-GET go to the backend;
  # the rest goes to the UI.
  proxy:
    image: nginx:1-alpine
    restart: unless-stopped
    configs:
      - source: nginx
        target: /etc/nginx/nginx.conf
    depends_on:
      - lemmy
      - lemmy-ui

  lemmy:
    image: dessalines/lemmy:0.19.20
    restart: unless-stopped
    environment:
      RUST_LOG: warn
    configs:
      - source: lemmy
        target: /config/config.hjson
    depends_on:
      db:
        condition: service_healthy
      pictrs:
        condition: service_started
    # The first start runs the migrations and makes the admin before it listens.
    healthcheck:
      test: ["CMD", "curl", "-fsS", "-o", "/dev/null", "http://127.0.0.1:8536/api/v3/site"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 180s

  lemmy-ui:
    image: dessalines/lemmy-ui:0.19.20
    restart: unless-stopped
    environment:
      LEMMY_UI_LEMMY_INTERNAL_HOST: lemmy:8536
      LEMMY_UI_LEMMY_EXTERNAL_HOST: ${HOST}
      LEMMY_UI_HTTPS: "true"
    depends_on:
      lemmy:
        condition: service_healthy
    # The image's own check runs once a minute; this one answers in ten seconds.
    healthcheck:
      test: ["CMD-SHELL", "curl -ILfSs http://localhost:1234/ > /dev/null || exit 1"]
      interval: 10s
      timeout: 10s
      retries: 3
      start_period: 30s

  pictrs:
    image: asonix/pictrs:0.5
    restart: unless-stopped
    environment:
      PICTRS__SERVER__API_KEY: ${PICTRS_API_KEY}
      # Kept light: no video transcoding, and small animations, as Lemmy's docs set them.
      PICTRS__MEDIA__VIDEO__ENABLE: "false"
      PICTRS__MEDIA__ANIMATION__MAX_WIDTH: 256
      PICTRS__MEDIA__ANIMATION__MAX_HEIGHT: 256
      PICTRS__MEDIA__ANIMATION__MAX_AREA: 65536
      PICTRS__MEDIA__ANIMATION__MAX_FRAME_COUNT: 400
    volumes:
      - pictrs:/mnt

  db:
    image: postgres:18-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: lemmy
      POSTGRES_USER: lemmy
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    # Lemmy's docs raise Docker's 64 MB: big queries fail with "could not resize shared memory segment".
    shm_size: 1g
    volumes:
      - db:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U lemmy -d lemmy"]
      interval: 5s
      timeout: 5s
      retries: 12
      start_period: 30s

configs:
  # Lemmy reads its settings from this file alone. `setup` makes the admin at the
  # first start, so no setup page is left open; the password is a multiline
  # string, which Hjson takes as written, quotes and backslashes included.
  lemmy:
    content: |
      {
        hostname: "${HOST}"
        database: {
          host: db
          password: "${DB_PASSWORD}"
        }
        pictrs: {
          url: "http://pictrs:8080/"
          api_key: "${PICTRS_API_KEY}"
          # Thumbnails of linked pages stay where they are, not copied into pict-rs.
          image_mode: "None"
        }
        setup: {
          admin_username: admin
          admin_password:
            '''
            ${ADMIN_PASSWORD}
            '''
          site_name: Lemmy
        }
      }

  # Lemmy's nginx_internal.conf (lemmy-ansible); $$ is a $ to Compose.
  nginx:
    content: |
      worker_processes auto;

      events {
          worker_connections 1024;
      }

      http {
          # Docker's DNS, asked at each request, so that a recreated container is found.
          resolver 127.0.0.11 valid=5s;

          # The visitor's address, from the machine's proxy.
          set_real_ip_from 10.0.0.0/8;
          set_real_ip_from 172.16.0.0/12;
          set_real_ip_from 192.168.0.0/16;

          map "$$request_method:$$http_accept" $$proxpass {
              default "http://lemmy-ui:1234";
              "~^(?:GET|HEAD):.*?application\/(?:activity|ld)\+json" "http://lemmy:8536";
              "~^(?!(GET|HEAD)).*:" "http://lemmy:8536";
          }

          server {
              set $$lemmy_ui "lemmy-ui:1234";
              set $$lemmy "lemmy:8536";
              listen 8536;
              server_name localhost;
              server_tokens off;

              # Uploads go to pict-rs through the backend.
              client_max_body_size 20M;

              proxy_set_header Host $$http_host;
              proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;

              location / {
                  proxy_pass $$proxpass;
                  rewrite ^(.+)/+$$ $$1 permanent;
              }

              location = /.well-known/security.txt {
                  proxy_pass "http://$$lemmy_ui";
              }

              location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known|version|sitemap.xml) {
                  proxy_pass "http://$$lemmy";
              }
          }
      }

volumes:
  pictrs:
  db: