nixos/gotosocial: init

Co-authored-by: Peder Bergebakken Sundt <pbsds@hotmail.com>
This commit is contained in:
misuzu 2023-05-19 21:18:17 +03:00
parent f0fb246118
commit 45ffb33514
7 changed files with 272 additions and 0 deletions

View file

@ -14,6 +14,8 @@
- [river](https://github.com/riverwm/river), A dynamic tiling wayland compositor. Available as [programs.river](#opt-programs.river.enable). - [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). - [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} ## Backward Incompatibilities {#sec-release-23.11-incompatibilities}

View file

@ -1188,6 +1188,7 @@
./services/web-apps/galene.nix ./services/web-apps/galene.nix
./services/web-apps/gerrit.nix ./services/web-apps/gerrit.nix
./services/web-apps/gotify-server.nix ./services/web-apps/gotify-server.nix
./services/web-apps/gotosocial.nix
./services/web-apps/grocy.nix ./services/web-apps/grocy.nix
./services/web-apps/pixelfed.nix ./services/web-apps/pixelfed.nix
./services/web-apps/healthchecks.nix ./services/web-apps/healthchecks.nix

View file

@ -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>
```

View file

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

View file

@ -306,6 +306,7 @@ in {
gonic = handleTest ./gonic.nix {}; gonic = handleTest ./gonic.nix {};
google-oslogin = handleTest ./google-oslogin {}; google-oslogin = handleTest ./google-oslogin {};
gotify-server = handleTest ./gotify-server.nix {}; gotify-server = handleTest ./gotify-server.nix {};
gotosocial = runTest ./web-apps/gotosocial.nix;
grafana = handleTest ./grafana {}; grafana = handleTest ./grafana {};
grafana-agent = handleTest ./grafana-agent.nix {}; grafana-agent = handleTest ./grafana-agent.nix {};
graphite = handleTest ./graphite.nix {}; graphite = handleTest ./graphite.nix {};

View file

@ -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$'")
'';
}

View file

@ -3,6 +3,7 @@
, fetchurl , fetchurl
, fetchFromGitHub , fetchFromGitHub
, buildGoModule , buildGoModule
, nixosTests
}: }:
let let
owner = "superseriousbusiness"; owner = "superseriousbusiness";
@ -44,6 +45,8 @@ buildGoModule rec {
# tests are working only on x86_64-linux # tests are working only on x86_64-linux
doCheck = stdenv.isLinux && stdenv.isx86_64; doCheck = stdenv.isLinux && stdenv.isx86_64;
passthru.tests.gotosocial = nixosTests.gotosocial;
meta = with lib; { meta = with lib; {
homepage = "https://gotosocial.org"; homepage = "https://gotosocial.org";
changelog = "https://github.com/superseriousbusiness/gotosocial/releases/tag/v${version}"; changelog = "https://github.com/superseriousbusiness/gotosocial/releases/tag/v${version}";