inputs: { config, pkgs, lib, ... } : let # add nginx reverse proxy and ACME web certificate add_nginx = true; nginx_ports = [ 80 443 ]; lemmy = { upstreamName = "lemmy"; dataDir = "/var/lib/lemmy"; ip = "127.0.0.1"; port = 1234; domain = "lemmy.gra.phi.te"; }; lemmy-ui = { upstreamName = "lemmy-ui"; ip = "127.0.0.1"; port = 8536; }; pict-rs = { ip = "127.0.0.1"; port = 8080; }; acmeDomain = lemmy.domain; nginxVhost = lemmy.domain; in { security.acme = lib.mkIf add_nginx { acceptTerms = true; defaults = { email = "ultra980@proton.me"; dnsProvider = "cloudflare"; credentialsFile = ./lemmy_credentials.txt; }; certs."${acmeDomain}" = { domain = "${acmeDomain}"; }; }; networking.firewall.allowedTCPPorts = lib.mkIf add_nginx nginx_ports; # is needed because of certificate file permissions users.users.nginx.extraGroups = lib.mkIf add_nginx ["acme"]; services.nginx = lib.mkIf add_nginx { upstreams."${lemmy.upstreamName}".servers."${lemmy.ip}:${builtins.toString lemmy.port}" = {}; upstreams."${lemmy-ui.upstreamName}".servers."${lemmy-ui.ip}:${builtins.toString lemmy-ui.port}" = {}; virtualHosts."${nginxVhost}" = { useACMEHost = "${acmeDomain}"; # inherit from config.security.acme.acmeRoot; acmeRoot = null; # add redirects from http to https forceSSL = true; # this whole block was lifted from https://github.com/LemmyNet/lemmy/blob/ef1aa18fd20cc03d492a81cb70cc75cf3281649f/docker/nginx.conf#L21 lines 21-32 extraConfig = '' # disables emitting nginx version on error pages and in the “Server” response header field 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"; ''; locations = { "/" = { # we do not use the nixos "locations..proxyPass" option because the nginx config needs to do something fancy. # again, lifted wholesale from https://github.com/LemmyNet/lemmy/blob/ef1aa18fd20cc03d492a81cb70cc75cf3281649f/docker/nginx.conf#L36 lines 36-55 extraConfig = '' # distinguish between ui requests and backend # don't change lemmy-ui or lemmy here, they refer to the upstream definitions on top set $proxpass "http://${lemmy-ui.upstreamName}"; if ($http_accept = "application/activity+json") { set $proxpass "http://${lemmy.upstreamName}"; } if ($http_accept = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") { set $proxpass "http://${lemmy.upstreamName}"; } if ($request_method = POST) { set $proxpass "http://${lemmy.upstreamName}"; } proxy_pass $proxpass; # Cuts off the trailing slash on URLs to make them valid 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; ''; }; # again, lifted wholesale from https://github.com/LemmyNet/lemmy/blob/ef1aa18fd20cc03d492a81cb70cc75cf3281649f/docker/nginx.conf#L60 lines 60-69 (nice!) "~ ^/(api|pictrs|feeds|nodeinfo|.well-known)" = { proxyPass = "http://${lemmy.upstreamName}"; extraConfig = '' # 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; ''; }; }; }; }; systemd.services.lemmy-ui = { environment = { LEMMY_UI_HOST = lib.mkForce "${lemmy-ui.ip}:${toString lemmy-ui.port}"; LEMMY_UI_LEMMY_INTERNAL_HOST = lib.mkForce "${lemmy.ip}:${toString lemmy.port}"; LEMMY_UI_LEMMY_EXTERNAL_HOST = lib.mkForce lemmy.domain ; LEMMY_UI_HTTPS="true"; }; }; services.pict-rs = { enable = true; port = pict-rs.port; dataDir = "${dataDir}/pict-rs"; address = pict-rs.ip; }; systemd.services.lemmy = { requires = ["postgresql.service"]; after = ["postgresql.service"]; environment = { LEMMY_DATABASE_URL = lib.mkForce "postgresql://lemmy@127.0.0.1:${toString config.services.postgresql.port}/lemmy"; }; }; services.lemmy = { enable = true; ui.port = lemmy-ui.port; database.createLocally = true; settings = { # TODO: Enable this much later when you tested everything. # N.B. you can't change your domain name after enabling this. federation.enabled = false; # settings related to the postgresql database database = { user = "lemmy"; password = "secretlemmypassword"; host = "127.0.0.1"; port = ${config.services.postgresql.port}; database = "lemmy"; pool_size = 5; }; /* # Pictrs image server configuration. pictrs = { # Address where pictrs is available (for image hosting) url = "http://${pict-rs.ip}:${toString pict-rs.port}/"; # TODO: Set a custom pictrs API key. ( Required for deleting images ) api_key = ""; }; */ # TODO: Email sending configuration. All options except login/password are mandatory email = { # Hostname and port of the smtp server smtp_server = ""; # Login name for smtp server smtp_login = ""; # Password to login to the smtp server smtp_password = ""; # Address to send emails from, eg "noreply@your-instance.com"; smtp_from_address = "noreply@${lemmy.domain}"; # Whether or not smtp connections should use tls. Can be none, tls, or starttls tls_type = "none"; }; # TODO: Parameters for automatic configuration of new instance (only used at first start) setup = { # Username for the admin user admin_username = "superawesomeadmin"; # Password for the admin user. It must be at least 10 characters. admin_password = ""; # Name of the site (can be changed later) site_name = "Lemmy at ${lemmy.domain}"; # Email for the admin user (optional, can be omitted and set later through the website) admin_email = "admin@${lemmy.domain}"; }; # the domain name of your instance (mandatory) hostname = lemmy.domain; # Address where lemmy should listen for incoming requests bind = lemmy.ip; # Port where lemmy should listen for incoming requests port = lemmy.port; # Whether the site is available over TLS. Needs to be true for federation to work. tls_enabled = true; }; }; # needed for now nixpkgs.config.permittedInsecurePackages = [ "nodejs-14.21.3" "openssl-1.1.1t" ]; system.activationScripts."make_sure_lemmy_user_owns_files" = '' uid='${config.users.users.lemmy.uid}'; gid='${config.users.groups.lemmy.gid}'; dir='${lemmy.dataDir}' mkdir -p "''${dir}" if [[ "$(${pkgs.toybox}/bin/stat "''${dir}" -c '%u:%g' | tee /dev/stderr )" != "''${uid}:''${gid}" ]]; then chown -R "''${uid}:''${gid}" "''${dir}" fi ''; }; }; }