Hello all!

I finally got my Lemmy instance up and running yay!

It runs on a local machine, I have nginx installed and my website pointing onto it.

lemmy.mindoki.com => my_static_ip(port 80) => local_ip => nginx

In ngunx I just set up a hello world message, and it works out. lemmy.mindoki.com shows it.

Now, my Lemmy instance is accessible on 0.0.0.0:1236 but obviously only from inside the hosting machine itself.

I have tinkered a bit with the nginx.conf but I feel there is lot of things to do wrongly, especially as it’s ‘dynamic’, but also it seems like a schoolbook example (for Lemmy, so no hits on my favourite search engine), so maybe someone has a working nginx.conf file to spare for a basic setup like this?

Thanks a bunch!

    • Valmond@lemmy.mlOP
      link
      fedilink
      arrow-up
      1
      ·
      1 year ago

      Thanks a bunch, but that is still quite incomprehensible for me, which means that either I’ll just fool around trying to get it right (which is not what I want to do) or learn it all the hard way (which I try to escape :-) ) or get some clever help ^^

      Should I change: default “http://lemmy-ui”; “~^(?!(GET|HEAD)).*:” “http://lemmy”; proxy_pass “http://lemmy”; to my website somehow (I have an A redirect from lemmy.mindoki.com to my external IP => route to the linux box)?

      Thanks again!

      • Max-P@lemmy.max-p.me
        link
        fedilink
        English
        arrow-up
        2
        ·
        1 year ago

        So, the part that selects what hostname it serves is the server_name directive. What those http://lemmy and http://lemmy-ui point to is the backend services. In this case, it’s assuming the Docker setup where the containers are named lemmy and lemmy-ui respectively. They’re completely invisible to the user, and in this case relies on Docker directing those names to the appropriate containers automatically. You don’t need to change those, unless you’re not using Docker. If you’re not using Docker, then those need to point to the address to reach lemmy and lemmy-ui. So for example, you might want to set that to http://127.0.0.1:1236.

        Essentially, traffic comes in at port 80/443 or whatever your listen directives say, then NGINX receives the connection and processes the host header in the request to match it against which server{} block serves that server_name, or falls back to whichever server block defines listen ..... default_server, or if there isn’t any, it usually falls into whichever server block happens to be first loaded in by the server. Pretty much only the listen and server_name directives are relevant here in terms of handling incoming traffic from the outside, mostly. Things like ssl_* will also configure how to handle incoming HTTPS connection, but that happens slightly after the server block has been identified using the listen and server_name directives. Most other directives are about how to handle the request once it’s in the server block.

        Then, it processes the request entirely within that server block. In this particular case, there’s a bit of logic so that it proxies it to lemmy-ui unless it’s an ActivityPub request or anything not a GET/HEAD request, in which case it tries to proxy it to the lemmy backend service. That’s what the if directives accomplish here. Usually we put those in location blocks, in this case the location / block so it handles all paths except other location blocks that override it. Some directives can be put directly in the server block and will apply to all locations unless overridden. Technically NGINX processes the location blocks first in order of precision (ie. /foo/bar/42/comments is more specific than /foo, and when there’s a tie it’s based on configuration order in the config file).

        There’s also a location block to map some URLs like /.well-known and /pictrs that also gets proxied to the lemmy backend directly. The way those work is say, you want to handle something at http://example.com/demo, you can add a location /demo {} block and the directives in that block will only apply when the URL is /demo/*.

        Does that clarify things for you?

        • Valmond@lemmy.mlOP
          link
          fedilink
          English
          arrow-up
          1
          ·
          1 year ago

          Thank you and yes, yes it does clarify a lot how nginx is working!

          I’m trying to use use the conf file coming with lemmy docker install, and after some searching I don’t even know if this is deprecated or not (it’s in the http{} ), or how I should tell nginx the information about where to find the docker devices:

          upstream lemmy {
              # this needs to map to the lemmy (server) docker service hostname
              server "lemmy:8536";
          }
          upstream lemmy-ui {
              # this needs to map to the lemmy-ui docker service hostname
              server "lemmy-ui:1234";
          }
          

          Also, shouldn’t I tell nginx to listen to port 80?

          Also, I get this error when I run “sudo nginx -s reload” and I don’t even understand what it means:

          nginx: [emerg] host not found in upstream “lemmy” in /etc/nginx/nginx.conf:53

          Thank you again, I’m a slow learner!

          • Max-P@lemmy.max-p.me
            link
            fedilink
            English
            arrow-up
            2
            ·
            1 year ago

            There’s two NGINX servers in the Docker setup: one on the inside, and one on the outside/on the host.

            If you run NGINX from the host or outside of the docker-compose, lemmy and lemmy-ui won’t resolve because that only exists within Docker. It does a bit of magic that essentially amounts to putting these in the containers’ /etc/hosts and maps to the internal IPs that the containers get. Docker has some sort of virtual router built-in, each compose gets its own virtual network and everything.

            If you use the Docker setup, you can use the configs I linked from the Ansible repo essentially as-is with minor tweaks. The internal NGINX config can be kept completely unchanged, and the outside one only needs minor tweaks to set up your own hostname and the port for the internal one. You only need to fill in the {{domain}} and {{lemmy_port}} placeholders in the outside one. The example outside NGINX config already listens to both 80 and 443.

            Basically with the suggested setup, you go Internet -> your server (port 80/443) -> the internal NGINX in Docker (port 1236) -> lemmy/lemmy-ui.

            • Valmond@lemmy.mlOP
              link
              fedilink
              English
              arrow-up
              1
              ·
              1 year ago

              Good morning and thank you, I’ll use your recommended config asap, and then be back with more questions most probably :-) !

            • Valmond@lemmy.mlOP
              link
              fedilink
              English
              arrow-up
              1
              ·
              edit-2
              1 year ago

              Hello !

              I followed your instructions, taking the:

              lemmy-ansible/templates/nginx_internal.conf
              

              and sticking:

              lemmy-ansible/templates/nginx.conf
              

              in the “http {” section + changing all the {{domain}} to lemmy.mindoki.com and changing the {{lemmy_port}} to 1236 (FYI: 0.0.0.0:1236 hits up Lemmy locally)

              Saving it all off in the nginx nginx.conf file.

              I feel exceedingly stupid, but is this the way to go? Because I get this error when I reload nginx:

              nginx: [emerg] host not found in upstream “lemmy:8536” in /etc/nginx/nginx.conf:111

              Cheers and thanks again!

              Edit: removing the upstreams, changed the backend proxy_pass, but to no avail…

              • Max-P@lemmy.max-p.me
                link
                fedilink
                English
                arrow-up
                2
                ·
                1 year ago

                Can you describe your setup in more details? Are you using the Docker setup with also NGINX running on the host outside of Docker?

                If so, nginx_internal.conf must be passed in as a volume to the inner NGINX via the docker-compose. On the host, you only need the bits from nginx.conf. Don’t try to use the internal ones, it doesn’t make sense.

                If you post your configs it will be easier to pinpoint exactly what’s wrong. Also paste the output of docker ps.

                • Valmond@lemmy.mlOP
                  link
                  fedilink
                  English
                  arrow-up
                  1
                  ·
                  1 year ago

                  I’m off one week on holidays, will sure post all config when I come back, thanks again!

                • Valmond@lemmy.mlOP
                  link
                  fedilink
                  English
                  arrow-up
                  1
                  ·
                  edit-2
                  1 year ago

                  Hello, I’m back with more questions and clarifications!

                  This is what I did to install Lemmy:

                  Install a fresh Linux Mint on an old PC.

                  Follow the ‘official’ docker install: https://join-lemmy.org/docs/administration/install_docker.html

                  I continued with nginx, lets encrypt etc.

                  I also installed PosgreSQL and added a user Lemmy.

                  I forward a TCP connection from my fix public IP to the lemmy PC and pointed lemmy.mindoki.com with an A redirection onto that public IP:PORT.

                  The only ‘exotic’ thing done was that I added these lines to /home/fediverse/.bashrc :

                  export LEMMY_CONFIG_LOCATION=“/media/fediverse/Storage/lemmy/lemmy.hjson”

                  EMMY_DATABASE_URL=“postgres://lemmy:redacted_password@localhost:5432/lemmy”

                  . “$HOME/.cargo/env”

                  I don’t think (but not completely sure) that the last line was added by me manually.

                  Now I can access Lemmy locally on localhost:1236 and everything works (inscription, creations of ‘subs’ etc).

                  I added the nginx.conf config file at the end of this message (some lines are commented out to make it work at all).

                  Almost feels like I should have a very much shorter nginx config file 🙃

                  Thanks again!

                  Cheers

                  .

                  .

                  .

                  nginx.conf :

                  worker_processes auto;

                  events { worker_connections 1024; }

                  http {

                  limit_req_zone $binary_remote_addr zone=lemmy.mindoki.com_ratelimit:10m rate=1r/s;
                  
                  server {
                      listen 80;
                      listen [::]:80;
                      server_name lemmy.mindoki.com;
                      # Hide nginx version
                      server_tokens off;
                      location /.well-known/acme-challenge/ {
                          root /var/www/certbot;
                      }
                      location / {
                          return 301 https://$host$request_uri;
                      }
                  }
                  
                  server {
                      listen 443 ssl http2;
                      listen [::]:443 ssl http2;
                      server_name lemmy.mindoki.com;
                  
                      ssl_certificate /etc/letsencrypt/live/lemmy.mindoki.com/fullchain.pem;
                      ssl_certificate_key /etc/letsencrypt/live/lemmy.mindoki.com/privkey.pem;
                  
                  
                      ssl_protocols TLSv1.2 TLSv1.3;
                      ssl_prefer_server_ciphers on;
                      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';
                      ssl_session_timeout  10m;
                      ssl_session_cache shared:SSL:10m;
                      ssl_session_tickets on;
                      ssl_stapling on;
                      ssl_stapling_verify on;
                  
                      # Hide nginx version
                      server_tokens 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;
                  
                      # 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";
                  
                  
                      location / {
                        proxy_pass http://0.0.0.0:1236;
                        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;
                      }
                  }
                  
                  access_log /var/log/nginx/access.log combined;
                  
                  
                  
                  # We construct a string consistent of the "request method" and "http accept header"
                  # and then apply soem ~simply regexp matches to that combination to decide on the
                  # HTTP upstream we should proxy the request to.
                  #
                  # Example strings:
                  #
                  #   "GET:application/activity+json"
                  #   "GET:text/html"
                  #   "POST:application/activity+json"
                  #
                  # You can see some basic match tests in this regex101 matching this configuration
                  # https://regex101.com/r/vwMJNc/1
                  #
                  # Learn more about nginx maps here http://nginx.org/en/docs/http/ngx_http_map_module.html
                  map "$request_method:$http_accept" $proxpass {
                      # If no explicit matches exists below, send traffic to lemmy-ui
                      default "http://lemmy-ui";
                  
                      # GET/HEAD requests that accepts ActivityPub or Linked Data JSON should go to lemmy.
                      #
                      # These requests are used by Mastodon and other fediverse instances to look up profile information,
                      # discover site information and so on.
                      "~^(?:GET|HEAD):.*?application\/(?:activity|ld)\+json" "http://lemmy";
                  
                      # All non-GET/HEAD requests should go to lemmy
                      #
                      # Rather than calling out POST, PUT, DELETE, PATCH, CONNECT and all the verbs manually
                      # we simply negate the GET|HEAD pattern from above and accept all possibly $http_accept values
                      "~^(?!(GET|HEAD)).*:" "http://lemmy";
                  }
                  
                  #upstream lemmy {
                      # this needs to map to the lemmy (server) docker service hostname
                  #    server "lemmy:8536";
                  #}
                  
                  #upstream lemmy-ui {
                      # this needs to map to the lemmy-ui docker service hostname
                  #    server "lemmy-ui:1234";
                  #}
                  
                  server {
                      # this is the port inside docker, not the public one yet
                      listen 1236;
                      listen 8536;
                  
                      # change if needed, this is facing the public web
                      server_name localhost;
                      server_tokens off;
                  
                      gzip on;
                      gzip_types text/css application/javascript image/svg+xml;
                      gzip_vary on;
                  
                      # Upload limit, relevant for pictrs
                      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";
                  
                      # frontend general requests
                      location / {
                          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;
                      }
                  
                      # backend
                      location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known) {
                          proxy_pass "https://lemmy";
                  
                          # proxy common stuff
                          proxy_http_version 1.1;
                          proxy_set_header Upgrade $http_upgrade;
                          proxy_set_header Connection "upgrade";
                  
                          # 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;
                      }
                  }
                  

                  }

      • phoenix591@lemmy.phoenix591.com
        link
        fedilink
        arrow-up
        1
        ·
        1 year ago

        you tell it what you mean by lemmy and lemmy-ui earlier in the config file outside of the server {} block

        upstream lemmy {
        # this needs to map to the lemmy (server) docker service hostname
        server “127.0.0.1:8536”;
        }
        upstream lemmy-ui {
        # this needs to map to the lemmy-ui docker service hostname
        server “127.0.0.1:1234”;
        }