Unverified Commit 067f44f7 authored by Sandro Jäckel's avatar Sandro Jäckel Committed by GitHub
Browse files

nixos/remark42: add module and test (#489715)

parents 804a1ef1 8dd7b3c1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@

- [qui](https://github.com/autobrr/qui), a modern alternative webUI for qBittorrent, with multi-instance support. Written in Go/React. Available as [services.qui](#opt-services.qui.enable).

- [Remark42](https://remark42.com/), a self-hosted comment engine. Available as [services.remark42](#opt-services.remark42.enable).

- [LibreChat](https://www.librechat.ai/), open-source self-hostable ChatGPT clone with Agents and RAG APIs. Available as [services.librechat](#opt-services.librechat.enable).

- [nohang](https://github.com/hakavlad/nohang), a daemon for Linux that prevents out of memory (OOM) situations from affecting system responsiveness. Available as [services.nohang](#opt-services.nohang.enable)
+1 −0
Original line number Diff line number Diff line
@@ -1738,6 +1738,7 @@
  ./services/web-apps/privatebin.nix
  ./services/web-apps/prosody-filer.nix
  ./services/web-apps/readeck.nix
  ./services/web-apps/remark42.nix
  ./services/web-apps/reposilite.nix
  ./services/web-apps/rimgo.nix
  ./services/web-apps/rss-bridge.nix
+143 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:

let
  cfg = config.services.remark42;
  siteList = lib.concatStringsSep "," cfg.sites;
in
{
  options.services.remark42 = {
    enable = lib.mkEnableOption "Remark42 commenting server";

    package = lib.mkPackageOption pkgs "remark42" { };

    remarkUrl = lib.mkOption {
      type = lib.types.str;
      example = "https://comments.example.com";
      description = ''
        Public URL of this Remark42 instance. This is passed to the backend as
        `REMARK_URL` and should match the frontend embed config `host`.
      '';
    };

    sites = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      default = [ "remark" ];
      example = [
        "blog"
        "docs"
      ];
      description = ''
        Site IDs served by this instance (passed as `SITE`, comma-separated).
        The frontend embed config `site_id` must match one of these values.
      '';
    };

    listenAddress = lib.mkOption {
      type = lib.types.str;
      default = "127.0.0.1";
      example = "0.0.0.0";
      description = "Bind address (`REMARK_ADDRESS`).";
    };

    port = lib.mkOption {
      type = lib.types.port;
      default = 8080;
      description = "Listen port (`REMARK_PORT`).";
    };

    dataDir = lib.mkOption {
      type = lib.types.path;
      default = "/var/lib/remark42";
      description = ''
        Working directory for Remark42. Data files are stored here and
        automatic backups will be created in this directory by default.
      '';
    };

    environmentFile = lib.mkOption {
      type = lib.types.nullOr lib.types.path;
      default = null;
      example = "/run/secrets/remark42.env";
      description = ''
        Optional environment file in systemd `EnvironmentFile=` format.
        Use this for secrets to avoid storing them in the Nix store.
      '';
    };

    settings = lib.mkOption {
      type = lib.types.attrsOf lib.types.str;
      default = { };
      example = {
        AUTH_ANON = "true";
      };
      description = "Extra environment variables passed to Remark42.";
    };

    openFirewall = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = "Whether to open the firewall for `port`.";
    };
  };

  config = lib.mkIf cfg.enable {
    assertions = [
      {
        assertion = cfg.sites != [ ];
        message = "services.remark42.sites must contain at least one site ID.";
      }
      {
        assertion = cfg.environmentFile != null || (cfg.settings ? SECRET);
        message = ''
          Remark42 requires SECRET.
          Provide it via services.remark42.environmentFile (recommended),
          or via services.remark42.settings.SECRET (not recommended).
        '';
      }
    ];

    users.groups.remark42 = { };
    users.users.remark42 = {
      isSystemUser = true;
      group = "remark42";
      home = cfg.dataDir;
      createHome = true;
      description = "Remark42 service user";
    };

    systemd.services.remark42 = {
      description = "Remark42 commenting server";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];

      environment = cfg.settings // {
        REMARK_URL = cfg.remarkUrl;
        SITE = siteList;
        REMARK_ADDRESS = cfg.listenAddress;
        REMARK_PORT = toString cfg.port;
      };

      serviceConfig = {
        Type = "simple";
        User = "remark42";
        Group = "remark42";

        WorkingDirectory = cfg.dataDir;
        ExecStart = "${cfg.package}/bin/remark42 server";

        Restart = "on-failure";
        RestartSec = "2s";
      }
      // lib.optionalAttrs (cfg.environmentFile != null) {
        EnvironmentFile = cfg.environmentFile;
      };
    };

    networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ];
  };
}
+1 −0
Original line number Diff line number Diff line
@@ -1390,6 +1390,7 @@ in
  redlib = runTest ./redlib.nix;
  redmine = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./redmine.nix { };
  refind = runTest ./refind.nix;
  remark42 = runTest ./remark42.nix;
  renovate = runTest ./renovate.nix;
  replace-dependencies = handleTest ./replace-dependencies { };
  reposilite = runTest ./reposilite.nix;
+30 −0
Original line number Diff line number Diff line
{ pkgs, ... }:

{
  name = "remark42";

  nodes.machine =
    { ... }:
    {
      environment.systemPackages = [ pkgs.curl ];

      services.remark42 = {
        enable = true;
        remarkUrl = "http://127.0.0.1:8080";
        sites = [ "remark" ];

        environmentFile = pkgs.writeText "remark42.env" ''
          SECRET=unit-test-secret
        '';

        settings.AUTH_ANON = "true";
      };
    };

  testScript = ''
    start_all()
    machine.wait_for_unit("remark42.service")
    machine.wait_for_open_port(8080)
    machine.succeed("curl -fsS http://127.0.0.1:8080/web/ | head")
  '';
}