commit 25ad27dd3c945858435079e63910c649eec14bed Author: niten Date: Fri Jul 7 22:11:33 2023 -0700 Fix flake diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..1673108 --- /dev/null +++ b/flake.nix @@ -0,0 +1,17 @@ +{ + description = "Lemmy via Docker Compose on NixOS"; + + inputs = { + nixpkgs.url = "nixpkgs/nixos-23.05"; + utils.url = "github:numtide/flake-utils"; + lemmyDockerCfg = { + url = + "https://raw.githubusercontent.com/LemmyNet/lemmy-ansible/main/templates/docker-compose.yml"; + flake = false; + }; + }; + + outputs = { self, nixpkgs, utils, lemmyDockerCfg, ... }: { + nixosModules.lemmyDocker = import ./lemmy-docker.nix; + }; +} diff --git a/lemmy-docker.nix b/lemmy-docker.nix new file mode 100644 index 0000000..43c4b8c --- /dev/null +++ b/lemmy-docker.nix @@ -0,0 +1,277 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + lemmyDockerImage = { hostname, lemmyDockerImage, lemmyUiDockerImage + , nginxCfgFile, pictrsApiKey, pictrsDockerImage, port, postgresDockerImage + , postgresPasswd, smtpServer, stateDirectory, ... }: + let + lemmyCfgFile = + lemmyCfg { inherit hostname postgresPasswd pictrsApiKey smtpServer; }; + lemmyDockerComposeCfgDir = lemmyDockerComposeCfg { + inherit hostname port lemmyCfgFile nginxCfgFile pictrsApiKey + stateDirectory postgresPasswd lemmyDockerImage lemmyUiDockerImage + pictrsDockerImage postgresDockerImage; + }; + in pkgs.stdenv.mkDerivation { + name = "lemmy-docker-image"; + src = lemmyDockerComposeCfgDir; + buildInputs = with pkgs; [ docker-compose ]; + buildPhase = "docker compose build"; + installPhase = "ls > $out"; + }; + + nginxCfg = writeTextFile "lemmy-nginx.conf" '' + 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; + } + } + } + ''; + + lemmyCfg = { hostname, postgresPasswd, pictrsApiKey, smtpServer, ... }: { + database = { + host = "postgres"; + password = postgresPasswd; + }; + hostname = hostname; + pictrs = { + url = "http://pictrs:8080/"; + api_key = pictrsApiKey; + }; + email = { + smtp_server = smtpServer; + tls_type = "none"; + smtp_from_address = "noreply@${hostname}"; + }; + }; + + lemmyDockerComposeCfg = { hostname, port, lemmyCfgFile, nginxCfgFile + , pictrsApiKey, stateDirectory, postgresPasswd, lemmyDockerImage + , lemmyUiDockerImage, pictrsDockerImage, postgresDockerImage, ... }: + let + defaultLogging = { + driver = "json-file"; + options = { + max-size = "50m"; + max-file = "4"; + }; + }; + in writeTextDir "docker-compose.yml" (toJSON { + version = "3.7"; + + services = { + proxy = { + image = "nginx:1-alpine"; + ports = [ "${port}:8536" ]; + volumes = [ "${nginxCfg}:/etc/nginx/nginx.conf:ro,Z" ]; + restart = "always"; + logging = defaultLogging; + }; + + lemmy = { + image = lemmyDockerImage; + hostname = "lemmy"; + restart = "always"; + logging = defaultLogging; + volumes = [ "${lemmyCfgFile}:/config/config.hjson:Z" ]; + depends_on = [ "postgres" "pictrs" ]; + }; + + lemmy-ui = { + image = lemmyUiDockerImage; + restart = "always"; + logging = defaultLogging; + depends_on = [ "lemmy" ]; + }; + + pictrs = { + image = pictrsDockerImage; + hostname = "pictrs"; + restart = "always"; + logging = defaultLogging; + user = "991:991"; + volumes = [ "${stateDirectory}/pictrs:/mnt:Z" ]; + deploy.resources.limits.memory = "690m"; + }; + + postgres = { + image = postgresDockerImage; + hostname = "postgres"; + restart = "always"; + logging = defaultLogging; + volumes = [ + "${stateDirectory}/database:/var/lib/postgresql/data:Z" + "${postgresCfg}:/etc/postgresql.conf" + ]; + }; + }; + }); + +in { + options.services.lemmyDocker = with types; { + enable = mkEnableOption "Enable Lemmy running in a Docker container."; + + hostname = mkOption { + type = str; + description = "Hostname at which this server is accessible."; + }; + + port = mkOption { + type = port; + description = "Port on which to listen for Lemmy connections."; + default = 8536; + }; + + version = mkOption { + type = str; + description = "Lemmy version."; + }; + + domain = mkOption { + type = str; + description = "Hostname at which Lemmy instance is reachable."; + }; + + state-directory = mkOption { + type = str; + description = "Directory at which to store application state."; + }; + + docker-images = { + lemmy = mkOption { + type = str; + description = "Docker image to use for Lemmy."; + }; + + lemmy-ui = mkOption { + type = str; + description = "Docker image to use for Lemmy UI."; + }; + + pictrs = mkOption { + type = str; + description = "Docker image to use for PictRs."; + }; + + postgres = mkOption { + type = str; + description = "Docker image to use for Postgres."; + }; + }; + }; + + config = mkIf cfg.enable (let + postgresPasswd = + readFile (pkgs.lib.passwd.random-passwd-file "lemmy-postgres-passwd" 30); + pictrsApiKey = + readFile (pkgs.lib.passwd.random-passwd-file "lemmy-pictrs-api-key" 30); + in { + fudo.secrets.host-secrets."${hostname}" = { + lemmyDockerEnv = { + source-file = writeTextFile "lemmy-docker-env" '' + PICTRS__API_KEY=\"${pictrsApiKey}\" + POSTGRES_PASSWORD=\"${postgresPassword}\" + ''; + }; + }; + + virtualisation = { + oci-containers.lemmy = { + environment = { + LEMMY_UI_LEMMY_INTERNAL_HOST = "lemmy:8536"; + LEMMY_UI_LEMMY_EXTERNAL_HOST = hostname; + LEMMY_UI_HTTPS = true; + PICTRS_OPENTELEMETRY_URL = "http://otel:4137"; + 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"; + POSTGRES_USER = "lemmy"; + POSTGRES_DB = "lemmy"; + }; + environmentFiles = [ hostSecrets.lemmyDockerEnv.target-file ]; + }; + }; + + services.nginx = { + enable = true; + virtualHosts."${cfg.hostname}" = { + enableACME = true; + forceSSL = true; + locations = { + "/" = { + proxyPass = "http://localhost:${toString cfg.port}"; + proxyWebsockets = true; + extraConfig = '' + proxy_set_header Host $host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + ''; + }; + }; + }; + }; + }); +}