From b824e341f515972659d30700ca249ed777db261e Mon Sep 17 00:00:00 2001 From: Fea Date: Tue, 12 Mar 2024 03:02:23 +0100 Subject: [PATCH 1/4] maintainers: add feathecutie (cherry picked from commit 70cf12a6d7a7eb86a0ba05f2ad703cfe76e19c28) --- maintainers/maintainer-list.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index ff068fa28ae5f..98c739486da30 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -6350,6 +6350,11 @@ githubId = 541748; name = "Felipe Espinoza"; }; + feathecutie = { + name = "feathecutie"; + github = "feathecutie"; + githubId = 53912746; + }; fedx-sudo = { email = "fedx-sudo@pm.me"; github = "FedX-sudo"; From 76384d5d190965fe8b0bbd259488076a17b71b83 Mon Sep 17 00:00:00 2001 From: Fea Date: Wed, 12 Jun 2024 16:06:37 +0200 Subject: [PATCH 2/4] misskey: init at 2024.5.0 (cherry picked from commit 564a6e61a0e0c6df9eda3baf78071ed59f722248) --- pkgs/by-name/mi/misskey/package.nix | 124 ++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 pkgs/by-name/mi/misskey/package.nix diff --git a/pkgs/by-name/mi/misskey/package.nix b/pkgs/by-name/mi/misskey/package.nix new file mode 100644 index 0000000000000..3261cf848baa8 --- /dev/null +++ b/pkgs/by-name/mi/misskey/package.nix @@ -0,0 +1,124 @@ +{ + stdenv, + lib, + nixosTests, + fetchFromGitHub, + nodejs, + pnpm, + makeWrapper, + python3, + bash, + jemalloc, + ffmpeg-headless, + writeShellScript, + ... +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "misskey"; + + version = "2024.5.0"; + + src = fetchFromGitHub { + owner = "misskey-dev"; + repo = finalAttrs.pname; + rev = finalAttrs.version; + hash = "sha256-nKf+SfuF6MQtNO53E6vN9CMDvQzKMv3PrD6gs9Qa86w="; + fetchSubmodules = true; + }; + + nativeBuildInputs = [ + nodejs + pnpm.configHook + makeWrapper + python3 + ]; + + # https://nixos.org/manual/nixpkgs/unstable/#javascript-pnpm + pnpmDeps = pnpm.fetchDeps { + inherit (finalAttrs) pname version src; + hash = "sha256-A1JBLa6lIw5tXFuD2L3vvkH6pHS5rlwt8vU2+UUQYdg="; + }; + + buildPhase = '' + runHook preBuild + + # https://github.com/NixOS/nixpkgs/pull/296697/files#r1617546739 + ( + cd node_modules/.pnpm/node_modules/v-code-diff + pnpm run postinstall + ) + + # https://github.com/NixOS/nixpkgs/pull/296697/files#r1617595593 + export npm_config_nodedir=${nodejs} + ( + cd node_modules/.pnpm/node_modules/re2 + pnpm run rebuild + ) + ( + cd node_modules/.pnpm/node_modules/sharp + pnpm run install + ) + + pnpm build + + runHook postBuild + ''; + + installPhase = + let + checkEnvVarScript = writeShellScript "misskey-check-env-var" '' + if [[ -z $MISSKEY_CONFIG_YML ]]; then + echo "MISSKEY_CONFIG_YML must be set to the location of the Misskey config file." + exit 1 + fi + ''; + in + '' + runHook preInstall + + mkdir -p $out/data + cp -r . $out/data + + # Set up symlink for use at runtime + # TODO: Find a better solution for this (potentially patch Misskey to make this configurable?) + # Line that would need to be patched: https://github.com/misskey-dev/misskey/blob/9849aab40283cbde2184e74d4795aec8ef8ccba3/packages/backend/src/core/InternalStorageService.ts#L18 + # Otherwise, maybe somehow bindmount a writable directory into /data/files. + ln -s /var/lib/misskey $out/data/files + + makeWrapper ${pnpm}/bin/pnpm $out/bin/misskey \ + --run "${checkEnvVarScript} || exit" \ + --chdir $out/data \ + --add-flags run \ + --set-default NODE_ENV production \ + --prefix PATH : ${ + lib.makeBinPath [ + nodejs + pnpm + bash + ] + } \ + --prefix LD_LIBRARY_PATH : ${ + lib.makeLibraryPath [ + jemalloc + ffmpeg-headless + stdenv.cc.cc.lib + ] + } + + runHook postInstall + ''; + + passthru = { + inherit (finalAttrs) pnpmDeps; + }; + + meta = { + description = "🌎 An interplanetary microblogging platform 🚀"; + homepage = "https://misskey-hub.net/"; + license = lib.licenses.agpl3Only; + maintainers = [ lib.maintainers.feathecutie ]; + platforms = lib.platforms.unix; + mainProgram = "misskey"; + }; +}) From 70ea7ba292ffc9d709fbb15f6675dc71f3aaa785 Mon Sep 17 00:00:00 2001 From: Fea Date: Wed, 12 Jun 2024 17:34:42 +0200 Subject: [PATCH 3/4] nixos/misskey: init (cherry picked from commit 0c9cb0041ba1835fe630d015be292cfc75922761) --- nixos/modules/module-list.nix | 1 + nixos/modules/services/web-apps/misskey.nix | 418 ++++++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/misskey.nix | 29 ++ pkgs/by-name/mi/misskey/package.nix | 1 + 5 files changed, 450 insertions(+) create mode 100644 nixos/modules/services/web-apps/misskey.nix create mode 100644 nixos/tests/misskey.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index b2c9a117c9a63..c0435dd79703e 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1401,6 +1401,7 @@ ./services/web-apps/meme-bingo-web.nix ./services/web-apps/microbin.nix ./services/web-apps/miniflux.nix + ./services/web-apps/misskey.nix ./services/web-apps/monica.nix ./services/web-apps/moodle.nix ./services/web-apps/movim.nix diff --git a/nixos/modules/services/web-apps/misskey.nix b/nixos/modules/services/web-apps/misskey.nix new file mode 100644 index 0000000000000..8a5c4bd927660 --- /dev/null +++ b/nixos/modules/services/web-apps/misskey.nix @@ -0,0 +1,418 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + cfg = config.services.misskey; + settingsFormat = pkgs.formats.yaml { }; + redisType = lib.types.submodule { + freeformType = lib.types.attrsOf settingsFormat.type; + options = { + host = lib.mkOption { + type = lib.types.str; + default = "localhost"; + description = "The Redis host."; + }; + port = lib.mkOption { + type = lib.types.port; + default = 6379; + description = "The Redis port."; + }; + }; + }; + settings = lib.mkOption { + description = '' + Configuration for Misskey, see + [`example.yml`](https://github.com/misskey-dev/misskey/blob/develop/.config/example.yml) + for all supported options. + ''; + type = lib.types.submodule { + freeformType = lib.types.attrsOf settingsFormat.type; + options = { + url = lib.mkOption { + type = lib.types.str; + example = "https://example.tld/"; + description = '' + The final user-facing URL. Do not change after running Misskey for the first time. + + This needs to match up with the configured reverse proxy and is automatically configured when using `services.misskey.reverseProxy`. + ''; + }; + port = lib.mkOption { + type = lib.types.port; + default = 3000; + description = "The port your Misskey server should listen on."; + }; + socket = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/path/to/misskey.sock"; + description = "The UNIX socket your Misskey server should listen on."; + }; + chmodSocket = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "777"; + description = "The file access mode of the UNIX socket."; + }; + db = lib.mkOption { + description = "Database settings."; + type = lib.types.submodule { + options = { + host = lib.mkOption { + type = lib.types.str; + default = "/var/run/postgresql"; + example = "localhost"; + description = "The PostgreSQL host."; + }; + port = lib.mkOption { + type = lib.types.port; + default = 5432; + description = "The PostgreSQL port."; + }; + db = lib.mkOption { + type = lib.types.str; + default = "misskey"; + description = "The database name."; + }; + user = lib.mkOption { + type = lib.types.str; + default = "misskey"; + description = "The user used for database authentication."; + }; + pass = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "The password used for database authentication."; + }; + disableCache = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to disable caching queries."; + }; + extra = lib.mkOption { + type = lib.types.nullOr (lib.types.attrsOf settingsFormat.type); + default = null; + example = { + ssl = true; + }; + description = "Extra connection options."; + }; + }; + }; + default = { }; + }; + redis = lib.mkOption { + type = redisType; + default = { }; + description = "`ioredis` options. See [`README`](https://github.com/redis/ioredis?tab=readme-ov-file#connect-to-redis) for reference."; + }; + redisForPubsub = lib.mkOption { + type = lib.types.nullOr redisType; + default = null; + description = "`ioredis` options for pubsub. See [`README`](https://github.com/redis/ioredis?tab=readme-ov-file#connect-to-redis) for reference."; + }; + redisForJobQueue = lib.mkOption { + type = lib.types.nullOr redisType; + default = null; + description = "`ioredis` options for the job queue. See [`README`](https://github.com/redis/ioredis?tab=readme-ov-file#connect-to-redis) for reference."; + }; + redisForTimelines = lib.mkOption { + type = lib.types.nullOr redisType; + default = null; + description = "`ioredis` options for timelines. See [`README`](https://github.com/redis/ioredis?tab=readme-ov-file#connect-to-redis) for reference."; + }; + meilisearch = lib.mkOption { + description = "Meilisearch connection options."; + type = lib.types.nullOr ( + lib.types.submodule { + options = { + host = lib.mkOption { + type = lib.types.str; + default = "localhost"; + description = "The Meilisearch host."; + }; + port = lib.mkOption { + type = lib.types.port; + default = 7700; + description = "The Meilisearch port."; + }; + apiKey = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "The Meilisearch API key."; + }; + ssl = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to connect via SSL."; + }; + index = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "Meilisearch index to use."; + }; + scope = lib.mkOption { + type = lib.types.enum [ + "local" + "global" + ]; + default = "local"; + description = "The search scope."; + }; + }; + } + ); + default = null; + }; + id = lib.mkOption { + type = lib.types.enum [ + "aid" + "aidx" + "meid" + "ulid" + "objectid" + ]; + default = "aidx"; + description = "The ID generation method to use. Do not change after starting Misskey for the first time."; + }; + }; + }; + }; +in + +{ + options = { + services.misskey = { + enable = lib.mkEnableOption "misskey"; + package = lib.mkPackageOption pkgs "misskey" { }; + inherit settings; + database = { + createLocally = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Create the PostgreSQL database locally. Sets `services.misskey.settings.db.{db,host,port,user,pass}`."; + }; + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "The path to a file containing the database password. Sets `services.misskey.settings.db.pass`."; + }; + }; + redis = { + createLocally = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Create and use a local Redis instance. Sets `services.misskey.settings.redis.host`."; + }; + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "The path to a file containing the Redis password. Sets `services.misskey.settings.redis.pass`."; + }; + }; + meilisearch = { + createLocally = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Create and use a local Meilisearch instance. Sets `services.misskey.settings.meilisearch.{host,port,ssl}`."; + }; + keyFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "The path to a file containing the Meilisearch API key. Sets `services.misskey.settings.meilisearch.apiKey`."; + }; + }; + reverseProxy = { + enable = lib.mkEnableOption "a HTTP reverse proxy for Misskey"; + webserver = lib.mkOption { + type = lib.types.attrTag { + nginx = lib.mkOption { + type = lib.types.submodule (import ../web-servers/nginx/vhost-options.nix); + default = { }; + description = '' + Extra configuration for the nginx virtual host of Misskey. + Set to `{ }` to use the default configuration. + ''; + }; + caddy = lib.mkOption { + type = lib.types.submodule ( + import ../web-servers/caddy/vhost-options.nix { cfg = config.services.caddy; } + ); + default = { }; + description = '' + Extra configuration for the caddy virtual host of Misskey. + Set to `{ }` to use the default configuration. + ''; + }; + }; + description = "The webserver to use as the reverse proxy."; + }; + host = lib.mkOption { + type = lib.types.nullOr lib.types.str; + description = '' + The fully qualified domain name to bind to. Sets `services.misskey.settings.url`. + + This is required when using `services.misskey.reverseProxy.enable = true`. + ''; + example = "misskey.example.com"; + default = null; + }; + ssl = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + description = '' + Whether to enable SSL for the reverse proxy. Sets `services.misskey.settings.url`. + + This is required when using `services.misskey.reverseProxy.enable = true`. + ''; + example = true; + default = null; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = + cfg.reverseProxy.enable -> ((cfg.reverseProxy.host != null) && (cfg.reverseProxy.ssl != null)); + message = "`services.misskey.reverseProxy.enable` requires `services.misskey.reverseProxy.host` and `services.misskey.reverseProxy.ssl` to be set."; + } + ]; + + services.misskey.settings = lib.mkMerge [ + (lib.mkIf cfg.database.createLocally { + db = { + db = lib.mkDefault "misskey"; + # Use unix socket instead of localhost to allow PostgreSQL peer authentication, + # required for `services.postgresql.ensureUsers` + host = lib.mkDefault "/var/run/postgresql"; + port = lib.mkDefault config.services.postgresql.settings.port; + user = lib.mkDefault "misskey"; + pass = lib.mkDefault null; + }; + }) + (lib.mkIf (cfg.database.passwordFile != null) { db.pass = lib.mkDefault "@DATABASE_PASSWORD@"; }) + (lib.mkIf cfg.redis.createLocally { redis.host = lib.mkDefault "localhost"; }) + (lib.mkIf (cfg.redis.passwordFile != null) { redis.pass = lib.mkDefault "@REDIS_PASSWORD@"; }) + (lib.mkIf cfg.meilisearch.createLocally { + meilisearch = { + host = lib.mkDefault "localhost"; + port = lib.mkDefault config.services.meilisearch.listenPort; + ssl = lib.mkDefault false; + }; + }) + (lib.mkIf (cfg.meilisearch.keyFile != null) { + meilisearch.apiKey = lib.mkDefault "@MEILISEARCH_KEY@"; + }) + (lib.mkIf cfg.reverseProxy.enable { + url = lib.mkDefault "${ + if cfg.reverseProxy.ssl then "https" else "http" + }://${cfg.reverseProxy.host}"; + }) + ]; + + systemd.services.misskey = { + after = [ + "network-online.target" + "postgresql.service" + ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = { + MISSKEY_CONFIG_YML = "/run/misskey/default.yml"; + }; + preStart = + '' + install -m 700 ${settingsFormat.generate "misskey-config.yml" cfg.settings} /run/misskey/default.yml + '' + + (lib.optionalString (cfg.database.passwordFile != null) '' + ${pkgs.replace-secret}/bin/replace-secret '@DATABASE_PASSWORD@' "${cfg.database.passwordFile}" /run/misskey/default.yml + '') + + (lib.optionalString (cfg.redis.passwordFile != null) '' + ${pkgs.replace-secret}/bin/replace-secret '@REDIS_PASSWORD@' "${cfg.redis.passwordFile}" /run/misskey/default.yml + '') + + (lib.optionalString (cfg.meilisearch.keyFile != null) '' + ${pkgs.replace-secret}/bin/replace-secret '@MEILISEARCH_KEY@' "${cfg.meilisearch.keyFile}" /run/misskey/default.yml + ''); + serviceConfig = { + ExecStart = "${cfg.package}/bin/misskey migrateandstart"; + RuntimeDirectory = "misskey"; + RuntimeDirectoryMode = "700"; + StateDirectory = "misskey"; + StateDirectoryMode = "700"; + TimeoutSec = 60; + DynamicUser = true; + User = "misskey"; + LockPersonality = true; + PrivateDevices = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectProc = "invisible"; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK"; + }; + }; + + services.postgresql = lib.mkIf cfg.database.createLocally { + enable = true; + ensureDatabases = [ "misskey" ]; + ensureUsers = [ + { + name = "misskey"; + ensureDBOwnership = true; + } + ]; + }; + + services.redis.servers = lib.mkIf cfg.redis.createLocally { + misskey = { + enable = true; + port = cfg.settings.redis.port; + }; + }; + + services.meilisearch = lib.mkIf cfg.meilisearch.createLocally { enable = true; }; + + services.caddy = lib.mkIf (cfg.reverseProxy.enable && cfg.reverseProxy.webserver ? caddy) { + enable = true; + virtualHosts.${cfg.settings.url} = lib.mkMerge [ + cfg.reverseProxy.webserver.caddy + { + hostName = lib.mkDefault cfg.settings.url; + extraConfig = '' + reverse_proxy localhost:${toString cfg.settings.port} + ''; + } + ]; + }; + + services.nginx = lib.mkIf (cfg.reverseProxy.enable && cfg.reverseProxy.webserver ? nginx) { + enable = true; + virtualHosts.${cfg.reverseProxy.host} = lib.mkMerge [ + cfg.reverseProxy.webserver.nginx + { + locations."/" = { + proxyPass = lib.mkDefault "http://localhost:${toString cfg.settings.port}"; + proxyWebsockets = lib.mkDefault true; + recommendedProxySettings = lib.mkDefault true; + }; + } + (lib.mkIf (cfg.reverseProxy.ssl != null) { forceSSL = lib.mkDefault cfg.reverseProxy.ssl; }) + ]; + }; + }; + + meta = { + maintainers = [ lib.maintainers.feathecutie ]; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 195a65156e7de..5db63d6154111 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -565,6 +565,7 @@ in { minio = handleTest ./minio.nix {}; miriway = handleTest ./miriway.nix {}; misc = handleTest ./misc.nix {}; + misskey = handleTest ./misskey.nix {}; mjolnir = handleTest ./matrix/mjolnir.nix {}; mobilizon = handleTest ./mobilizon.nix {}; mod_perl = handleTest ./mod_perl.nix {}; diff --git a/nixos/tests/misskey.nix b/nixos/tests/misskey.nix new file mode 100644 index 0000000000000..1a450c518aaeb --- /dev/null +++ b/nixos/tests/misskey.nix @@ -0,0 +1,29 @@ +import ./make-test-python.nix ( + { lib, ... }: + let + port = 61812; + in + { + name = "misskey"; + + meta.maintainers = [ lib.maintainers.feathecutie ]; + + nodes.machine = { + services.misskey = { + enable = true; + settings = { + url = "http://misskey.local"; + inherit port; + }; + database.createLocally = true; + redis.createLocally = true; + }; + }; + + testScript = '' + machine.wait_for_unit("misskey.service") + machine.wait_for_open_port(${toString port}) + machine.succeed("curl --fail http://localhost:${toString port}/") + ''; + } +) diff --git a/pkgs/by-name/mi/misskey/package.nix b/pkgs/by-name/mi/misskey/package.nix index 3261cf848baa8..1c364e7c3a5ff 100644 --- a/pkgs/by-name/mi/misskey/package.nix +++ b/pkgs/by-name/mi/misskey/package.nix @@ -111,6 +111,7 @@ stdenv.mkDerivation (finalAttrs: { passthru = { inherit (finalAttrs) pnpmDeps; + tests.misskey = nixosTests.misskey; }; meta = { From 0a887773b56eea92293533749e63028eead3562c Mon Sep 17 00:00:00 2001 From: Chatnoir Miki Date: Tue, 24 Sep 2024 09:55:57 +0800 Subject: [PATCH 4/4] doc: backport misskey to 24.05 --- nixos/doc/manual/release-notes/rl-2405.section.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index c14e10d4a38eb..c1a4a060315f0 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -140,6 +140,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - [Mihomo](https://github.com/MetaCubeX/mihomo/tree/Alpha), a rule-based proxy in Go. Available as [services.mihomo.enable](#opt-services.mihomo.enable). +- [Misskey](https://github.com/misskey-dev/misskey), an interplanetary microblogging platform. Available as [services.misskey](#opt-services.misskey.enable). + - [Monado](https://monado.freedesktop.org/), an open source XR runtime. Available as [services.monado](#opt-services.monado.enable). - [Netbird](https://netbird.io), an open-source VPN management platform, now has a self-hosted management server. Available as [services.netbird.server](#opt-services.netbird.server.enable).