1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.gotosocial;
9 settingsFormat = pkgs.formats.yaml { };
10 configFile = settingsFormat.generate "config.yml" cfg.settings;
11 defaultSettings = {
12 application-name = "gotosocial";
13
14 protocol = "https";
15
16 bind-address = "127.0.0.1";
17 port = 8080;
18
19 storage-local-base-path = "/var/lib/gotosocial/storage";
20
21 db-type = "sqlite";
22 db-address = "/var/lib/gotosocial/database.sqlite";
23 };
24 gotosocial-admin = pkgs.writeShellScriptBin "gotosocial-admin" ''
25 exec systemd-run \
26 -u gotosocial-admin.service \
27 -p Group=gotosocial \
28 -p User=gotosocial \
29 -q -t -G --wait --service-type=exec \
30 ${cfg.package}/bin/gotosocial --config-path ${configFile} admin "$@"
31 '';
32in
33{
34 meta.doc = ./gotosocial.md;
35 meta.maintainers = with lib.maintainers; [ blakesmith ];
36
37 options.services.gotosocial = {
38 enable = lib.mkEnableOption "ActivityPub social network server";
39
40 package = lib.mkPackageOption pkgs "gotosocial" { };
41
42 openFirewall = lib.mkOption {
43 type = lib.types.bool;
44 default = false;
45 description = ''
46 Open the configured port in the firewall.
47 Using a reverse proxy instead is highly recommended.
48 '';
49 };
50
51 setupPostgresqlDB = lib.mkOption {
52 type = lib.types.bool;
53 default = false;
54 description = ''
55 Whether to setup a local postgres database and populate the
56 `db-type` fields in `services.gotosocial.settings`.
57 '';
58 };
59
60 settings = lib.mkOption {
61 type = settingsFormat.type;
62 default = defaultSettings;
63 example = {
64 application-name = "My GoToSocial";
65 host = "gotosocial.example.com";
66 };
67 description = ''
68 Contents of the GoToSocial YAML config.
69
70 Please refer to the
71 [documentation](https://docs.gotosocial.org/en/latest/configuration/)
72 and
73 [example config](https://github.com/superseriousbusiness/gotosocial/blob/main/example/config.yaml).
74
75 Please note that the `host` option cannot be changed later so it is important to configure this correctly before you start GoToSocial.
76 '';
77 };
78
79 environmentFile = lib.mkOption {
80 type = lib.types.nullOr lib.types.path;
81 description = ''
82 File path containing environment variables for configuring the GoToSocial service
83 in the format of an EnvironmentFile as described by {manpage}`systemd.exec(5)`.
84
85 This option could be used to pass sensitive configuration to the GoToSocial daemon.
86
87 Please refer to the Environment Variables section in the
88 [documentation](https://docs.gotosocial.org/en/latest/configuration/).
89 '';
90 default = null;
91 example = "/root/nixos/secrets/gotosocial.env";
92 };
93
94 };
95
96 config = lib.mkIf cfg.enable {
97 assertions = [
98 {
99 assertion = cfg.settings.host or null != null;
100 message = ''
101 You have to define a hostname for GoToSocial (`services.gotosocial.settings.host`), it cannot be changed later without starting over!
102 '';
103 }
104 ];
105
106 services.gotosocial.settings =
107 (lib.mapAttrs (name: lib.mkDefault) (
108 defaultSettings
109 // {
110 web-asset-base-dir = "${cfg.package}/share/gotosocial/web/assets/";
111 web-template-base-dir = "${cfg.package}/share/gotosocial/web/template/";
112 }
113 ))
114 // (lib.optionalAttrs cfg.setupPostgresqlDB {
115 db-type = "postgres";
116 db-address = "/run/postgresql";
117 db-database = "gotosocial";
118 db-user = "gotosocial";
119 });
120
121 environment.systemPackages = [ gotosocial-admin ];
122
123 users.groups.gotosocial = { };
124 users.users.gotosocial = {
125 group = "gotosocial";
126 isSystemUser = true;
127 };
128
129 networking.firewall = lib.mkIf cfg.openFirewall {
130 allowedTCPPorts = [ cfg.settings.port ];
131 };
132
133 services.postgresql = lib.mkIf cfg.setupPostgresqlDB {
134 enable = true;
135 ensureDatabases = [ "gotosocial" ];
136 ensureUsers = [
137 {
138 name = "gotosocial";
139 ensureDBOwnership = true;
140 }
141 ];
142 };
143
144 systemd.services.gotosocial = {
145 description = "ActivityPub social network server";
146 wantedBy = [ "multi-user.target" ];
147 after = [ "network.target" ] ++ lib.optional cfg.setupPostgresqlDB "postgresql.target";
148 requires = lib.optional cfg.setupPostgresqlDB "postgresql.target";
149 restartTriggers = [ configFile ];
150
151 serviceConfig = {
152 EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
153 ExecStart = "${cfg.package}/bin/gotosocial --config-path ${configFile} server start";
154 Restart = "on-failure";
155 Group = "gotosocial";
156 User = "gotosocial";
157 StateDirectory = "gotosocial";
158 WorkingDirectory = "/var/lib/gotosocial";
159
160 # Security options:
161 # Based on https://github.com/superseriousbusiness/gotosocial/blob/v0.8.1/example/gotosocial.service
162 AmbientCapabilities = lib.optional (cfg.settings.port < 1024) "CAP_NET_BIND_SERVICE";
163 NoNewPrivileges = true;
164 PrivateTmp = true;
165 PrivateDevices = true;
166 RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
167 RestrictNamespaces = true;
168 RestrictRealtime = true;
169 DevicePolicy = "closed";
170 ProtectSystem = "full";
171 ProtectControlGroups = true;
172 ProtectKernelModules = true;
173 ProtectKernelTunables = true;
174 LockPersonality = true;
175 };
176 };
177 };
178}