Note: this is my crosspost from reddit. Hello folks! I’ve been trying to get my own Lemmy instance up and had some problems figuring out how to set it up for realsies in production.

Perhaps you like to play self hosting on hard mode like I do. Perhaps you looked at the ansible playbook for Lemmy and said ‘absolutely not’. Perhaps you saw you could also build it from scratch, and oh nevermind there’s a docker, cool. That’s what Portainer is for, you crazy son of a gun!! Perhaps you then looked at the Docker guide, saw that nginx was part of the deployment and said ‘I could probably move that to my currently existing Nginx Proxy Manager!’

You’d be right, but it might cost you hours of time, tears, sweat, and some sanity. Like me! I hope this helps someone!

To start:

SSH into your docker box. You’ll need to create a few volumes and download some stuff. I elected to create my files at /docker/lemmy.

mkdir /docker/lemmy/
cd /docker/lemmy/
mkdir -p volumes/pictrs
sudo chown -R 991:991 volumes/pictrs

Download the ‘lemmy.hjson’ config file by doing a

wget https://raw.githubusercontent.com/LemmyNet/lemmy/release/v0.17/docker/prod/lemmy.hjson

Edit that sucker.

Change the stuff between < > (and remove the <>s). If there are ""s it’s intentional. Here’s how mine looks. Take note: It starts and ends with { } brackets.


{
  # for more info about the config, check out the documentation
  # https://join-lemmy.org/docs/en/administration/configuration.html

  # only few config options are covered in this example config

  setup: {
    # username for the admin user
    admin_username: <"astronguser">
    # password for the admin user
    admin_password: <"astrongpassword">
    # name of the site (can be changed later)
    site_name: <"acoolname">
  }

  # the domain name of your instance (eg "lemmy.ml" or "fernchat.esotericmonkey.com")
  hostname: <"fakelemmy.horse">
  # 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

  # pictrs host
  pictrs: {
    url: "http://pictrs:8080/"
    # api_key: "API_KEY"
  }

  # settings related to the postgresql database
  database: {
    # name of the postgres database for lemmy
    database: <"databasename">
    # username to connect to postgres
    user: <"astronguser">
    # password to connect to postgres
    password: <"astrongpassword">
    # host where postgres is running. This needs to match the postgres hostname in the portainer stack
    host: "postgres"
    # port where postgres can be accessed
    port: 5432
    # maximum number of active sql connections
    pool_size: 5
  }


# See the documentation for available config fields and descriptions:
# https://join-lemmy.org/docs/en/administration/configuration.html
  federation: {
  hostname: <fakelemmy.horse>
  allowed_instances: <lemmy_ml>
}

  email: {
    # Hostname and port of the smtp server
    smtp_server: <"mail.server.com:465">
    # Login name for smtp server
    smtp_login: <"lemmy@server.com">
    # Password to login to the smtp server
    smtp_password: <"12345">
    # Address to send emails from, eg "noreply@your-instance.com"
    smtp_from_address: <"noreply@server.com">
    # Whether or not smtp connections should use tls. Can be none, tls, or starttls
    tls_type: "tls"
  }
}

Download the docker-compose.yml to your computer. Go to Portainer, and create a new stack.

Paste the content of that files into the stack, edit it, and create it.Here’s how my compose file looks. This keeps the database on the lemmyinternal network. It exposes the UI and lemmy to the LAN. My Portainer IP is 172.16.7.20. Update the variables inside < >!

version: "3.3"
networks:
  #Keep the database safe, dawg
  lemmyinternal:
    driver: bridge
    internal: true
  lemmyexternal:
  #Everything else
services:

  lemmy:
    image: dessalines/lemmy:0.17.3
    networks:
      - lemmyinternal
      - lemmyexternal
    ports:
     - 8536:8536
    restart: always
    environment:
      - RUST_LOG="warn,lemmy_server=info,lemmy_api=info,lemmy_api_common=info,lemmy_api_crud=info,lemmy_apub=info,lemmy_db_schema=info,lemmy_db_views=info,lemmy_db_views_actor=info,lemmy_db_views_moderator=info,lemmy_routes=info,lemmy_utils=info,lemmy_websocket=info"
      #Set RUST_BACKTRACE=1 if you have problems, or if you just want to feel clever looking at log files
      - RUST_BACKTRACE=1
    volumes:
      - /docker/lemmy/lemmy.hjson:/config/config.hjson
    depends_on:
      - postgres
      - pictrs

  lemmy-ui:
    image: dessalines/lemmy-ui:0.17.3
    networks:
      - lemmyexternal
    ports:
    #Always keep em guessing
      - 1236:1234
    environment:
      # THIS SHOULD BE 'lemmy'. IT'S THE NAME OF THE DOCKER SEVICE NOT A HOSTNAME
      - LEMMY_UI_LEMMY_INTERNAL_HOST=lemmy:8536
      # set the outside hostname here. I use 1236 as the port, make sure you have 1236:1234 for your lemmy-ui port if so.
      - LEMMY_UI_LEMMY_EXTERNAL_HOST=<172.16.7.20:1236>
      #Nginx Proxy Manager will get this.
      - LEMMY_HTTPS=false
    depends_on:
      - lemmy
    restart: always

  pictrs:
    networks:
      - lemmyinternal
    image: asonix/pictrs:0.3.1
    # this needs to match the pictrs url in lemmy.hjson
    hostname: pictrs
    # we can set options to pictrs like this, here we set max. image size and forced format for conversion
    # entrypoint: /sbin/tini -- /usr/local/bin/pict-rs -p /mnt -m 4 --image-format webp
    environment:
      - PICTRS__API_KEY=API_KEY
    user: 991:991
    volumes:
      - /docker/lemmy/volumes/pictrs:/mnt
    restart: always

  postgres:
    networks:
      - lemmyinternal
    image: postgres:15-alpine
    # this needs to match the database host in lemmy.hson
    hostname: postgres
    ports:
      - 5432:5432
    environment:
      - POSTGRES_USER=<strongusername>
      - POSTGRES_PASSWORD=<strongpassword>
      - POSTGRES_DB=<databasename>
    volumes:
      - /docker/lemmy/volumes/postgres:/var/lib/postgresql/data
    restart: always

Note: if this fails the first time and you get database errors in postgres, or lemmy won’t shut up about being unable to access the database or settings, you may need to destroy the stack containers, remove all non-persistent volumes, and do a rm -rf on the /docker/lemmy/volumes/postgres folder.

If you check the database logs in Portainer, you should see the database initalizing for the first time, and lemmy should be running a migration process.

Pop over to Nginx Proxy Manager and create a new site. In my case, I’ll be pointing towards http://172.16.7.20:1236.

Enable Websockets Support.

Under SSL, acquire your Lets Encrypt Certificate

(or install your own, you crazy admin!).

Enable ‘Force SSL’ and ‘HTTPS/2 Support’.

You may enable HSTS if you’d like.

Under Custom Locations, you’ll need a few!


location: /api http://172.16.7.20:8536

location: /pictrs http://172.16.7.20:8536

location: /feeds http://172.16.7.20:8536

location: /nodeinfo http://172.16.7.20:8536

Then, go to the advanced tab, and paste in this block. This makes the federation all federationy.


location / {
      # The default ports:
      # lemmy_ui_port: 1235(not used here)
      # lemmy_port: 8536
      # The cooler port:
      # lemmy_ui_port: 1236

      set $proxpass "http://172.16.7.20:1236";
      if ($http_accept ~ "^application/.*$") {
        set $proxpass "http://172.16.7.20:8536";
      }
      if ($request_method = POST) {
        set $proxpass "http://172.16.7.20:8536";
      }
      proxy_pass $proxpass;

      rewrite ^(.+)/+$ $1 permanent;

      # Send actual client IP upstream
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

Hit save. In theory, you should have a working Lemmy instance. See you in the fediverse!