at master 9.6 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.services.sharkey; 10 11 settingsFormat = pkgs.formats.yaml { }; 12 configFile = settingsFormat.generate "config.yml" cfg.settings; 13in 14{ 15 options.services.sharkey = 16 let 17 inherit (lib) 18 mkEnableOption 19 mkOption 20 mkPackageOption 21 types 22 ; 23 in 24 { 25 enable = mkEnableOption "Sharkey, a Sharkish microblogging platform"; 26 package = mkPackageOption pkgs "sharkey" { }; 27 28 environmentFiles = mkOption { 29 type = types.listOf types.path; 30 default = [ ]; 31 example = [ "/run/secrets/sharkey-env" ]; 32 description = '' 33 List of paths to files containing environment variables for Sharkey to use at runtime. 34 35 This is useful for keeping secrets out of the Nix store. See 36 <https://docs.joinsharkey.org/docs/install/configuration/> for how to configure Sharkey using environment 37 variables. 38 ''; 39 }; 40 41 openFirewall = mkOption { 42 type = types.bool; 43 default = false; 44 example = true; 45 description = '' 46 Whether to open ports in the NixOS firewall for Sharkey. 47 ''; 48 }; 49 50 setupMeilisearch = mkOption { 51 type = types.bool; 52 default = false; 53 example = true; 54 description = '' 55 Whether to automatically set up a local Meilisearch instance and configure Sharkey to use it. 56 57 You need to ensure `services.meilisearch.masterKeyFile` is correctly configured for a working 58 Meilisearch setup. You also need to configure Sharkey to use an API key obtained from Meilisearch with the 59 `MK_CONFIG_MEILISEARCH_APIKEY` environment variable, and set `services.sharkey.settings.meilisearch.index` to 60 the created index. See <https://docs.joinsharkey.org/docs/customisation/search/meilisearch/> for how to create 61 an API key and index. 62 ''; 63 }; 64 65 setupPostgresql = mkOption { 66 type = types.bool; 67 default = true; 68 example = false; 69 description = '' 70 Whether to automatically set up a local PostgreSQL database and configure Sharkey to use it. 71 ''; 72 }; 73 74 setupRedis = mkOption { 75 type = types.bool; 76 default = true; 77 example = false; 78 description = '' 79 Whether to automatically set up a local Redis cache and configure Sharkey to use it. 80 ''; 81 }; 82 83 settings = mkOption { 84 type = types.submodule { 85 freeformType = settingsFormat.type; 86 options = { 87 url = mkOption { 88 type = types.str; 89 example = "https://blahaj.social/"; 90 description = '' 91 The full URL that the Sharkey instance will be publically accessible on. 92 93 Do NOT change this after initial setup! 94 ''; 95 }; 96 97 port = mkOption { 98 type = types.port; 99 default = 3000; 100 description = '' 101 The port that Sharkey will listen on. 102 ''; 103 }; 104 105 address = mkOption { 106 type = types.str; 107 default = "0.0.0.0"; 108 example = "127.0.0.1"; 109 description = '' 110 The address that Sharkey binds to. 111 ''; 112 }; 113 114 socket = mkOption { 115 type = types.nullOr types.path; 116 default = null; 117 example = "/run/sharkey/sharkey.sock"; 118 description = '' 119 If specified, creates a UNIX socket at the given path that Sharkey listens on. 120 ''; 121 }; 122 123 mediaDirectory = mkOption { 124 type = types.path; 125 default = "/var/lib/sharkey"; 126 description = '' 127 Path to the folder where Sharkey stores uploaded media such as images and attachments. 128 ''; 129 }; 130 131 fulltextSearch.provider = mkOption { 132 type = types.enum [ 133 "sqlLike" 134 "sqlPgroonga" 135 "sqlTsvector" 136 "meilisearch" 137 ]; 138 default = "sqlLike"; 139 example = "sqlPgroonga"; 140 description = '' 141 Which provider to use for full text search. 142 143 All options other than `sqlLike` require extra setup - see the comments in 144 <https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/.config/example.yml> for details. 145 146 If `sqlPgroonga` is set, and `services.sharkey.setupPostgres` is `true`, the pgroonga extension will 147 automatically be setup. You still need to create an index manually. 148 149 If using Meilisearch, consider setting `services.sharkey.setupMeilisearch` instead, which will 150 configure Meilisearch for you. 151 ''; 152 }; 153 154 id = mkOption { 155 type = types.enum [ 156 "aid" 157 "aidx" 158 "meid" 159 "ulid" 160 "objectid" 161 ]; 162 default = "aidx"; 163 description = '' 164 The ID generation method for Sharkey to use. 165 166 Do NOT change this after initial setup! 167 ''; 168 }; 169 }; 170 }; 171 default = { }; 172 description = '' 173 Configuration options for Sharkey. 174 175 See <https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/.config/example.yml> for a list of all 176 available configuration options. 177 ''; 178 }; 179 }; 180 181 config = 182 let 183 inherit (lib) mkDefault mkIf mkMerge; 184 in 185 mkIf cfg.enable (mkMerge [ 186 { 187 systemd.services.sharkey = { 188 description = "Sharkey"; 189 documentation = [ "https://docs.joinsharkey.org/" ]; 190 wantedBy = [ "multi-user.target" ]; 191 startLimitBurst = 5; 192 startLimitIntervalSec = 60; 193 environment.MISSKEY_CONFIG_DIR = "/etc/sharkey"; 194 195 serviceConfig = { 196 Type = "simple"; 197 ExecStart = "${lib.getExe cfg.package} migrateandstart"; 198 EnvironmentFile = cfg.environmentFiles; 199 DynamicUser = true; 200 TimeoutSec = 60; 201 Restart = "always"; 202 SyslogIdentifier = "sharkey"; 203 ConfigurationDirectory = "sharkey"; 204 RuntimeDirectory = "sharkey"; 205 StateDirectory = "sharkey"; 206 CapabilityBoundingSet = ""; 207 LockPersonality = true; 208 NoNewPrivileges = true; 209 PrivateDevices = true; 210 PrivateUsers = true; 211 PrivateTmp = true; 212 ProcSubset = "pid"; 213 ProtectClock = true; 214 ProtectControlGroups = true; 215 ProtectHome = true; 216 ProtectHostname = true; 217 ProtectKernelLogs = true; 218 ProtectKernelModules = true; 219 ProtectKernelTunables = true; 220 ProtectProc = "invisible"; 221 ProtectSystem = "strict"; 222 ReadWritePaths = [ cfg.settings.mediaDirectory ]; 223 RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK"; 224 RestrictNamespaces = true; 225 RestrictRealtime = true; 226 SystemCallArchitectures = "native"; 227 SystemCallFilter = [ 228 "~@cpu-emulation @debug @mount @obsolete @privileged @resources" 229 "@chown" 230 ]; 231 UMask = "0077"; 232 }; 233 }; 234 235 environment.etc."sharkey/default.yml".source = configFile; 236 } 237 (mkIf cfg.openFirewall { 238 networking.firewall.allowedTCPPorts = [ cfg.settings.port ]; 239 }) 240 (mkIf cfg.setupMeilisearch { 241 services.meilisearch = { 242 enable = mkDefault true; 243 settings.env = mkDefault "production"; 244 }; 245 246 services.sharkey.settings = { 247 fulltextSearch.provider = "meilisearch"; 248 meilisearch = { 249 host = config.services.meilisearch.listenAddress; 250 port = config.services.meilisearch.listenPort; 251 }; 252 }; 253 254 systemd.services.sharkey = { 255 after = [ "meilisearch.service" ]; 256 wants = [ "meilisearch.service" ]; 257 }; 258 }) 259 (mkIf cfg.setupPostgresql { 260 services.postgresql = { 261 enable = mkDefault true; 262 ensureDatabases = [ "sharkey" ]; 263 ensureUsers = [ 264 { 265 name = "sharkey"; 266 ensureDBOwnership = true; 267 } 268 ]; 269 270 extensions = mkIf (cfg.settings.fulltextSearch.provider == "sqlPgroonga") (ps: [ ps.pgroonga ]); 271 }; 272 273 services.sharkey.settings.db = { 274 host = "/run/postgresql"; 275 db = "sharkey"; 276 }; 277 278 systemd.services.sharkey = { 279 after = [ "postgresql.target" ]; 280 bindsTo = [ "postgresql.target" ]; 281 }; 282 }) 283 (mkIf cfg.setupRedis { 284 services.redis.servers.sharkey.enable = mkDefault true; 285 286 services.sharkey.settings.redis.path = config.services.redis.servers.sharkey.unixSocket; 287 288 systemd.services.sharkey = { 289 after = [ "redis-sharkey.service" ]; 290 bindsTo = [ "redis-sharkey.service" ]; 291 292 serviceConfig.SupplementaryGroups = [ 293 config.services.redis.servers.sharkey.group 294 ]; 295 }; 296 }) 297 ]); 298 299 meta.maintainers = with lib.maintainers; [ 300 tmarkus 301 ]; 302}