about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authormisuzu <bakalolka@gmail.com>2023-05-19 21:18:17 +0300
committermisuzu <bakalolka@gmail.com>2023-06-05 09:07:34 +0300
commit45ffb33514488fd27b9355081a687db8312d97f4 (patch)
tree5eee1440472a320903ef3f4b4524e84872ca7399 /nixos
parentf0fb24611876f48151defbe1df51401ae926a150 (diff)
downloadnixlib-45ffb33514488fd27b9355081a687db8312d97f4.tar
nixlib-45ffb33514488fd27b9355081a687db8312d97f4.tar.gz
nixlib-45ffb33514488fd27b9355081a687db8312d97f4.tar.bz2
nixlib-45ffb33514488fd27b9355081a687db8312d97f4.tar.lz
nixlib-45ffb33514488fd27b9355081a687db8312d97f4.tar.xz
nixlib-45ffb33514488fd27b9355081a687db8312d97f4.tar.zst
nixlib-45ffb33514488fd27b9355081a687db8312d97f4.zip
nixos/gotosocial: init
Co-authored-by: Peder Bergebakken Sundt <pbsds@hotmail.com>
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/rl-2311.section.md2
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/services/web-apps/gotosocial.md64
-rw-r--r--nixos/modules/services/web-apps/gotosocial.nix173
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/web-apps/gotosocial.nix28
6 files changed, 269 insertions, 0 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md
index 6f770757edba..8f67999433f0 100644
--- a/nixos/doc/manual/release-notes/rl-2311.section.md
+++ b/nixos/doc/manual/release-notes/rl-2311.section.md
@@ -14,6 +14,8 @@
 
 - [river](https://github.com/riverwm/river), A dynamic tiling wayland compositor. Available as [programs.river](#opt-programs.river.enable).
 
+- [GoToSocial](https://gotosocial.org/), an ActivityPub social network server, written in Golang. Available as [services.gotosocial](#opt-services.gotosocial.enable).
+
 - [sitespeed-io](https://sitespeed.io), a tool that can generate metrics (timings, diagnostics) for websites. Available as [services.sitespeed-io](#opt-services.sitespeed-io.enable).
 
 ## Backward Incompatibilities {#sec-release-23.11-incompatibilities}
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 83b2a45dbd3b..42230f4524c5 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -1188,6 +1188,7 @@
   ./services/web-apps/galene.nix
   ./services/web-apps/gerrit.nix
   ./services/web-apps/gotify-server.nix
+  ./services/web-apps/gotosocial.nix
   ./services/web-apps/grocy.nix
   ./services/web-apps/pixelfed.nix
   ./services/web-apps/healthchecks.nix
diff --git a/nixos/modules/services/web-apps/gotosocial.md b/nixos/modules/services/web-apps/gotosocial.md
new file mode 100644
index 000000000000..a290d7d1893a
--- /dev/null
+++ b/nixos/modules/services/web-apps/gotosocial.md
@@ -0,0 +1,64 @@
+# GoToSocial {#module-services-gotosocial}
+
+[GoToSocial](https://gotosocial.org/) is an ActivityPub social network server, written in Golang.
+
+## Service configuration {#modules-services-gotosocial-service-configuration}
+
+The following configuration sets up the PostgreSQL as database backend and binds
+GoToSocial to `127.0.0.1:8080`, expecting to be run behind a HTTP proxy on `gotosocial.example.com`.
+
+```nix
+services.gotosocial = {
+  enable = true;
+  setupPostgresqlDB = true;
+  settings = {
+    application-name = "My GoToSocial";
+    host = "gotosocial.example.com";
+    protocol = "https";
+    bind-address = "127.0.0.1";
+    port = 8080;
+  };
+};
+```
+
+Please refer to the [GoToSocial Documentation](https://docs.gotosocial.org/en/latest/configuration/general/)
+for additional configuration options.
+
+## Proxy configuration {#modules-services-gotosocial-proxy-configuration}
+
+Although it is possible to expose GoToSocial directly, it is common practice to operate it behind an
+HTTP reverse proxy such as nginx.
+
+```nix
+networking.firewall.allowedTCPPorts = [ 80 443 ];
+services.nginx = {
+  enable = true;
+  clientMaxBodySize = "40M";
+  virtualHosts = with config.services.gotosocial.settings; {
+    "${host}" = {
+      enableACME = true;
+      forceSSL = true;
+      locations = {
+        "/" = {
+          recommendedProxySettings = true;
+          proxyWebsockets = true;
+          proxyPass = "http://${bind-address}:${toString port}";
+        };
+      };
+    };
+  };
+};
+```
+
+Please refer to [](#module-security-acme) for details on how to provision an SSL/TLS certificate.
+
+## User management {#modules-services-gotosocial-user-management}
+
+After the GoToSocial service is running, the `gotosocial-admin` utility can be used to manage users. In particular an
+administrative user can be created with
+
+```ShellSession
+$ sudo gotosocial-admin account create --username <nickname> --email <email> --password <password>
+$ sudo gotosocial-admin account confirm --username <nickname>
+$ sudo gotosocial-admin account promote --username <nickname>
+```
diff --git a/nixos/modules/services/web-apps/gotosocial.nix b/nixos/modules/services/web-apps/gotosocial.nix
new file mode 100644
index 000000000000..f7ae018d5b7c
--- /dev/null
+++ b/nixos/modules/services/web-apps/gotosocial.nix
@@ -0,0 +1,173 @@
+{ config, lib, pkgs, ... }:
+let
+  cfg = config.services.gotosocial;
+  settingsFormat = pkgs.formats.yaml { };
+  configFile = settingsFormat.generate "config.yml" cfg.settings;
+  defaultSettings = {
+    application-name = "gotosocial";
+
+    protocol = "https";
+
+    bind-address = "127.0.0.1";
+    port = 8080;
+
+    storage-local-base-path = "/var/lib/gotosocial/storage";
+
+    db-type = "sqlite";
+    db-address = "/var/lib/gotosocial/database.sqlite";
+  };
+  gotosocial-admin = pkgs.writeShellScriptBin "gotosocial-admin" ''
+    exec systemd-run \
+      -u gotosocial-admin.service \
+      -p Group=gotosocial \
+      -p User=gotosocial \
+      -q -t -G --wait --service-type=exec \
+      ${cfg.package}/bin/gotosocial --config-path ${configFile} admin "$@"
+  '';
+in
+{
+  meta.doc = ./gotosocial.md;
+  meta.maintainers = with lib.maintainers; [ misuzu ];
+
+  options.services.gotosocial = {
+    enable = lib.mkEnableOption (lib.mdDoc "ActivityPub social network server");
+
+    package = lib.mkPackageOptionMD pkgs "gotosocial" { };
+
+    openFirewall = lib.mkOption {
+      type = lib.types.bool;
+      default = false;
+      description = lib.mdDoc ''
+        Open the configured port in the firewall.
+        Using a reverse proxy instead is highly recommended.
+      '';
+    };
+
+    setupPostgresqlDB = lib.mkOption {
+      type = lib.types.bool;
+      default = false;
+      description = lib.mdDoc ''
+        Whether to setup a local postgres database and populate the
+        `db-type` fields in `services.gotosocial.settings`.
+      '';
+    };
+
+    settings = lib.mkOption {
+      type = settingsFormat.type;
+      default = defaultSettings;
+      example = {
+        application-name = "My GoToSocial";
+        host = "gotosocial.example.com";
+      };
+      description = lib.mdDoc ''
+        Contents of the GoToSocial YAML config.
+
+        Please refer to the
+        [documentation](https://docs.gotosocial.org/en/latest/configuration/)
+        and
+        [example config](https://github.com/superseriousbusiness/gotosocial/blob/main/example/config.yaml).
+
+        Please note that the `host` option cannot be changed later so it is important to configure this correctly before you start GoToSocial.
+      '';
+    };
+
+    environmentFile = lib.mkOption {
+      type = lib.types.nullOr lib.types.path;
+      description = lib.mdDoc ''
+        File path containing environment variables for configuring the GoToSocial service
+        in the format of an EnvironmentFile as described by systemd.exec(5).
+
+        This option could be used to pass sensitive configuration to the GoToSocial daemon.
+
+        Please refer to the Environment Variables section in the
+        [documentation](https://docs.gotosocial.org/en/latest/configuration/).
+      '';
+      default = null;
+      example = "/root/nixos/secrets/gotosocial.env";
+    };
+
+  };
+
+  config = lib.mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = cfg.settings.host or null != null;
+        message = ''
+          You have to define a hostname for GoToSocial (`services.gotosocial.settings.host`), it cannot be changed later without starting over!
+        '';
+      }
+    ];
+
+    services.gotosocial.settings = (lib.mapAttrs (name: lib.mkDefault) (
+      defaultSettings // {
+        web-asset-base-dir = "${cfg.package}/share/gotosocial/web/assets/";
+        web-template-base-dir = "${cfg.package}/share/gotosocial/web/template/";
+      }
+    )) // (lib.optionalAttrs cfg.setupPostgresqlDB {
+      db-type = "postgres";
+      db-address = "/run/postgresql";
+      db-database = "gotosocial";
+      db-user = "gotosocial";
+    });
+
+    environment.systemPackages = [ gotosocial-admin ];
+
+    users.groups.gotosocial = { };
+    users.users.gotosocial = {
+      group = "gotosocial";
+      isSystemUser = true;
+    };
+
+    networking.firewall = lib.mkIf cfg.openFirewall {
+      allowedTCPPorts = [ cfg.settings.port ];
+    };
+
+    services.postgresql = lib.mkIf cfg.setupPostgresqlDB {
+      enable = true;
+      ensureDatabases = [ "gotosocial" ];
+      ensureUsers = [
+        {
+          name = "gotosocial";
+          ensurePermissions = {
+            "DATABASE gotosocial" = "ALL PRIVILEGES";
+          };
+        }
+      ];
+    };
+
+    systemd.services.gotosocial = {
+      description = "ActivityPub social network server";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ]
+        ++ lib.optional cfg.setupPostgresqlDB "postgresql.service";
+      requires = lib.optional cfg.setupPostgresqlDB "postgresql.service";
+      restartTriggers = [ configFile ];
+
+      serviceConfig = {
+        EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
+        ExecStart = "${cfg.package}/bin/gotosocial --config-path ${configFile} server start";
+        Restart = "on-failure";
+        Group = "gotosocial";
+        User = "gotosocial";
+        StateDirectory = "gotosocial";
+        WorkingDirectory = "/var/lib/gotosocial";
+
+        # Security options:
+        # Based on https://github.com/superseriousbusiness/gotosocial/blob/v0.8.1/example/gotosocial.service
+        AmbientCapabilities = lib.optional (cfg.settings.port < 1024) "CAP_NET_BIND_SERVICE";
+        NoNewPrivileges = true;
+        PrivateTmp = true;
+        PrivateDevices = true;
+        RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        DevicePolicy = "closed";
+        ProtectSystem = "full";
+        ProtectControlGroups = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        LockPersonality = true;
+      };
+    };
+  };
+}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index e597a26f31bb..7937e1e15b20 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -306,6 +306,7 @@ in {
   gonic = handleTest ./gonic.nix {};
   google-oslogin = handleTest ./google-oslogin {};
   gotify-server = handleTest ./gotify-server.nix {};
+  gotosocial = runTest ./web-apps/gotosocial.nix;
   grafana = handleTest ./grafana {};
   grafana-agent = handleTest ./grafana-agent.nix {};
   graphite = handleTest ./graphite.nix {};
diff --git a/nixos/tests/web-apps/gotosocial.nix b/nixos/tests/web-apps/gotosocial.nix
new file mode 100644
index 000000000000..6d279ab63a79
--- /dev/null
+++ b/nixos/tests/web-apps/gotosocial.nix
@@ -0,0 +1,28 @@
+{ lib, ... }:
+{
+  name = "gotosocial";
+  meta.maintainers = with lib.maintainers; [ misuzu ];
+
+  nodes.machine = { pkgs, ... }: {
+    environment.systemPackages = [ pkgs.jq ];
+    services.gotosocial = {
+      enable = true;
+      setupPostgresqlDB = true;
+      settings = {
+        host = "localhost:8081";
+        port = 8081;
+      };
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("gotosocial.service")
+    machine.wait_for_unit("postgresql.service")
+    machine.wait_for_open_port(8081)
+
+    # check user registration via cli
+    machine.succeed("curl -sS -f http://localhost:8081/nodeinfo/2.0 | jq '.usage.users.total' | grep -q '^0$'")
+    machine.succeed("gotosocial-admin account create --username nickname --email email@example.com --password kurtz575VPeBgjVm")
+    machine.succeed("curl -sS -f http://localhost:8081/nodeinfo/2.0 | jq '.usage.users.total' | grep -q '^1$'")
+  '';
+}