Abhinav's Notes

Self-hosting GoToSocial on NixOS

GoToSocial is an ActivityPub server. It is a lightweight alternative to Mastodon, and very suitable for self-hosting single user instances1. Though it does not have all of Mastodon’s features (it’s getting there), it is already quite useable.

I decided to self-host GoToSocial on my VPS (which runs NixOS), pointing to my own domain. So instead of having a fediverse address like @abnv@mastodon.social, I’d have an address @abnv@soc.abnv.me2.

First, we package GoToSocial for NixOS:

{ pkgs }:

let
  pname = "gotosocial";
  version = "0.5.2";
in pkgs.stdenv.mkDerivation {
  inherit pname version;
  src = pkgs.fetchzip {
    url = "https://github.com/superseriousbusiness/${pname}/releases/download/v${version}/${pname}_${version}_linux_amd64.tar.gz";
    sha256 = "sha256-AfHXsQm0NHaqoyv7Jg6LHqzHmuahBiyAqHIBbY6rDJg=";
    stripRoot = false;
  };
  installPhase = ''
    mkdir -p "$out"/bin
    mv gotosocial $out/bin/
    mv web $out/
  '';
}
nix/packages/gotosocial.nix

Next, we write a minimal3 NixOS module to run GoToSocial:

{ options, lib, config, pkgs, ... }:

let
  serverName = "soc.abnv.me";
  port = 9755;
  userName = "gotosocial";
  serviceName = userName;
  dataDir = "/var/lib/${userName}";
  pkg = import ./nix/packages/gotosocial.nix { inherit pkgs; };
  yaml = pkgs.formats.yaml { };
  configFile = yaml.generate "${serviceName}.yaml" {
    host = serverName;
    bind-address = "localhost";
    port = port;
    db-type = "sqlite";
    db-address = "${dataDir}/data/sqlite.db";
    web-template-base-dir = "${pkg}/web/template/";
    web-asset-base-dir = "${pkg}/web/assets/";
    accounts-registration-open = false;
    storage-local-base-path = "${dataDir}/media";
  };
  serviceConfig = config.services."${serverName}";
  options = { enable = lib.mkEnableOption "${serverName} service"; };
in {
  options.services.${serverName} = options;
  config = lib.mkIf serviceConfig.enable {
    users.users.${userName} = {
      isSystemUser = true;
      group = userName;
      createHome = true;
      home = dataDir;
    };
    users.groups.${userName} = { };

    systemd.tmpfiles.rules = [
      "d ${dataDir}/data 1770 ${userName} ${userName}"
      "d ${dataDir}/media 1770 ${userName} ${userName}"
    ];

    systemd.services.${serviceName} = {
      enable = true;
      description = "${serviceName} service";
      restartIfChanged = true;
      restartTriggers = [ configFile pkg ];
      wantedBy = [ "multi-user.target" ];
      serviceConfig = {
        User = userName;
        Group = userName;
        WorkingDirectory = dataDir;
        ExecStart = "${pkg}/bin/gotosocial --config-path ${configFile} server start";
      };
    };

    services.nginx.virtualHosts.${serverName} = {
      forceSSL = true;
      enableACME = true;
      locations."/" = {
        proxyPass = "http://127.0.0.1:${port}";
        extraConfig = ''
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection $connection_upgrade;
        '';
      };
      extraConfig = ''
        client_max_body_size 40M;
      '';
    };
  };
}

First, we set up a user and a group for GoToSocial, and the directories for data and uploaded media. Then, we create the config file. We are using SQLite as the database here4. Next, we set up a Systemd service to run the GoToSocial binary with the created config file. Finally, we set up an Nginx virtual host to proxy requests to the GoToSocial process.

When we import and enable this module in our NixOS configuration, we have a self-hosted GoToSocial instance running. I have mine at soc.abnv.me, and you can follow me at @abnv@abnv.me.

That’s it for now. Happy #twittermigration.

Like, share or comment on this post on Mastodon.

  1. GoToSocial provides only the backend server. You’ll need a frontend as well. Pinafore on web, or Tusky on Android work well. 

  2. It is also possible to have an address like @abnv@abnv.me with some extra configuration

  3. There are couple of ways we can improve this module:

    • By adding sandboxing for the GoToSocial process.
    • By adding automatic restarts on failures.
    • By adding a separate route in Nginx for better caching of public assets.

  4. GoToSocial also supports PostgreSQL