Installing Lemmy 0.18.1 with Docker on Ubuntu

Last update: 2023-07-07

Why?

Because we want to use a federated forum and link aggregator :)

What do I need to install?

You need a Linux Server with Docker, and Docker-compose installed. creating directories

What's my setup?

Where I can find out more about the project?

How I can install it?

creating directories

mkdir -p /opt/lemmy
mkdir -p /opt/lemmy/{docker,data,config}
mkdir -p /opt/lemmy/data/{postgresql,pictrs,themes}
mkdir -p /opt/lemmy/config/{lemmy,postgresql,nginx}

defining permissions

chown -R 991:991 /opt/lemmy/data/pictrs

nginx config

creating the nginx.conf file

vim /opt/lemmy/config/nginx/nginx.conf

content

worker_processes auto;

events {
    worker_connections 1024;
}

http {

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

    upstream lemmy {
        server "lemmy:8536";
    }

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

    server {
        listen 1236;
        listen 8536;

        server_name localhost;
        server_tokens off;

        gzip on;
        gzip_types text/css application/javascript image/svg+xml;
        gzip_vary on;

        client_max_body_size 20M;

        add_header X-Frame-Options SAMEORIGIN;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";

        location / {
            proxy_pass $proxpass;
            rewrite ^(.+)/+$ $1 permanent;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        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;
        }
    }
}

lemmy backend config

creating the lemmy config file

vim /opt/lemmy/config/config.hjson

content

{
  database: {
    host: postgres
    password: "your_postgresql_password_here"
  }
  hostname: "bolha.forum"
  pictrs: {
    url: "http://pictrs:8080/"
    api_key: "your_postgresql_password_here"
  }
  email: {
    smtp_server: "postfix:25"
    smtp_from_address: "noreply@bolha.forum"
    tls_type: "none"
  }
}

docker config

creating the docker-compose.yaml

vim /opt/lemmy/docker/docker-compose.yml

content

version: "3.7"

services:

  proxy:
    image: nginx:1-alpine
    container_name: lemmy_proxy
    ports:
      - "8000:8536"
    volumes:
      - /opt/lemmy/config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro,Z
    restart: always
    depends_on:
      - pictrs
      - lemmy-ui

  lemmy:
    image: dessalines/lemmy:0.18.1
    container_name: lemmy_backend
    hostname: lemmy
    restart: always
    environment:
      - RUST_LOG="warn"
    volumes:
      - lemmy_config:/config
    depends_on:
      - postgres
      - pictrs

  lemmy-ui:
    image: dessalines/lemmy-ui:0.18.1
    container_name: lemmy_frontend
    environment:
      - LEMMY_UI_LEMMY_INTERNAL_HOST=lemmy:8536
      - LEMMY_UI_LEMMY_EXTERNAL_HOST=bolha.forum
      - LEMMY_UI_HTTPS=true
    volumes:
      - extra_themes:/app/extra_themes
    depends_on:
      - lemmy
    restart: always

  pictrs:
    image: asonix/pictrs:0.4.0-rc.7
    container_name: lemmy_images_backend
    hostname: pictrs
    environment:
      - PICTRS__API_KEY=your_postgresql_password_here
      - RUST_LOG=debug
      - RUST_BACKTRACE=full
      - 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
    user: 991:991
    volumes:
      - pictrs:/mnt:Z
    restart: always
    deploy:
      resources:
        limits:
          memory: 690m

  postgres:
    image: postgres:15-alpine
    container_name: lemmy_database
    hostname: postgres
    environment:
      - POSTGRES_USER=lemmy
      - POSTGRES_PASSWORD=your_postgresql_password_here
      - POSTGRES_DB=lemmy
    volumes:
      - postgresql:/var/lib/postgresql/data:Z
      - /opt/lemmy/config/postgresql/postgresql.conf:/etc/postgresql.conf
    restart: always

  postfix:
    image: mwader/postfix-relay
    container_name: lemmy_smtp_relay
    environment:
      - POSTFIX_myhostname=bolha.forum
      - POSTFIX_smtp_sasl_auth_enable= yes
      - POSTFIX_smtp_sasl_password_maps=static:user@domain.tld:user_password_here
      - POSTFIX_smtp_sasl_security_options=noanonymous
      - POSTFIX_relayhost=smtp.domain.tld:587
    restart: "always"

volumes:
  lemmy_config:
    driver_opts:
      type: none
      device: /opt/lemmy/config/lemmy
      o: bind
  extra_themes:
    driver_opts:
      type: none
      device: /opt/lemmy/data/themes
      o: bind
  pictrs:
    driver_opts:
      type: none
      device: /opt/lemmy/data/pictrs
      o: bind
  postgresql:
    driver_opts:
      type: none
      device: /opt/lemmy/data/postgresql
      o: bind

spinning up the lemmy instance

$ cd /opt/lemmy/docker
$ docker-compose up -d

checking

$ docker-compose ps

NAME                   IMAGE                        COMMAND                  SERVICE             CREATED             STATUS              PORTS
lemmy_backend          dessalines/lemmy:0.18.1      "/app/lemmy"             lemmy               34 minutes ago      Up 34 minutes
lemmy_database         postgres:15-alpine           "docker-entrypoint.s…"   postgres            34 minutes ago      Up 34 minutes       5432/tcp
lemmy_frontend         dessalines/lemmy-ui:0.18.1   "docker-entrypoint.s…"   lemmy-ui            34 minutes ago      Up 34 minutes       1234/tcp
lemmy_images_backend   asonix/pictrs:0.4.0-rc.7     "/sbin/tini -- /usr/…"   pictrs              34 minutes ago      Up 34 minutes       6669/tcp, 8080/tcp
lemmy_proxy            nginx:1-alpine               "/docker-entrypoint.…"   proxy               34 minutes ago      Up 34 minutes       80/tcp, 0.0.0.0:8000->8536/tcp, :::8000->8536/tcp
lemmy_smtp_relay       mwader/postfix-relay         "/root/run"              postfix             34 minutes ago      Up 34 minutes       25/tcp

You can see that our lemmy_proxy (nginx) is running on the port 8000.

Now let's configure the external reverse proxy.

external reverse-proxy config

certbot + letsencrypt

we're using cloudflare plugin with certbot, you need to have the configuration ready, like this example

# cat /etc/letsencrypt/cloudflare/bolha-forum.conf
dns_cloudflare_email = dns@bolha.forum
dns_cloudflare_api_key = your_token_here

then you can generate the certificate

# certbot certonly --dns-cloudflare --dns-cloudflare-credential /etc/letsencrypt/cloudflare/bolha-forum.conf -d "*.bolha.forum,bolha.forum"

now we can configure our nginx!

nginx config

external reverse proxy

server {
    listen your_listen_ip_here:80;
    server_name bolha.forum;
    location / {
        return 301 https://bolha.forum$request_uri;
    }
}

server {
    listen your_listen_ip_here:443 ssl http2;
    server_name bolha.forum;

    ssl_certificate /etc/letsencrypt/live/bolha.forum/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/bolha.forum/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;

    ssl_dhparam /etc/letsencrypt/dh-param.pem;

    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';

    # Specifies a curve for ECDHE ciphers.
    ssl_ecdh_curve prime256v1;

    # Server should determine the ciphers, not the client
    ssl_prefer_server_ciphers on;

    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    # Enable compression for JS/CSS/HTML bundle, for improved client load times.
    # It might be nice to compress JSON, but leaving that out to protect against potential
    # compression+encryption information leak attacks like BREACH.
    gzip on;
    gzip_types text/css application/javascript image/svg+xml;
    gzip_vary on;

    # Only connect to this site via HTTPS for the two years
    add_header Strict-Transport-Security "max-age=63072000";

    # Various content security headers
    add_header Referrer-Policy "same-origin";
    add_header X-Content-Type-Options "nosniff";
    add_header X-Frame-Options "DENY";
    add_header X-XSS-Protection "1; mode=block";

    # Upload limit for pictrs
    client_max_body_size 25M;


    location / {
      proxy_pass http://your_docker_host_ip_here:your_port_here;
      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;
    }
}

check the config

nginx -t

expected output

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

and reload the configuration

# nginx -s reload

that's it!

Go to your lemmy!

Now you can access your lemmy instance

Enjoy!


Did you like our content?

We have a lot to share; visit our site!

Our fediverse services ;)

Chat and video? We have it!

Translation tools

Video Platform Frontends

Text Editors

You can also visit our hacking space!

Follow our founder!

Follow the status of our tools

Do you want to support us? You can!

See you!

[s]