summary refs log tree commit diff
path: root/nixos/modules/services/web-apps/gotosocial.nix
blob: 9c21719a57590216b3da1f377e08ebbe1fdffb0e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
{ 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";
          ensureDBOwnership = true;
        }
      ];
    };

    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;
      };
    };
  };
}