nixpkgs/nixos/modules/services/web-apps/akkoma.md
Janne Heß fcc95ff817 treewide: Fix all Nix ASTs in all markdown files
This allows for correct highlighting and maybe future automatic
formatting. The AST was verified to work with nixfmt only.
2024-03-28 09:28:12 +01:00

11 KiB
Raw Blame History

Akkoma

Akkoma is a lightweight ActivityPub microblogging server forked from Pleroma.

Service configuration

The Elixir configuration file required by Akkoma is generated automatically from {option}services.akkoma.config. Secrets must be included from external files outside of the Nix store by setting the configuration option to an attribute set containing the attribute {option}_secret a string pointing to the file containing the actual value of the option.

For the mandatory configuration settings these secrets will be generated automatically if the referenced file does not exist during startup, unless disabled through {option}services.akkoma.initSecrets.

The following configuration binds Akkoma to the Unix socket /run/akkoma/socket, expecting to be run behind a HTTP proxy on fediverse.example.com.

{
  services.akkoma.enable = true;
  services.akkoma.config = {
    ":pleroma" = {
      ":instance" = {
        name = "My Akkoma instance";
        description = "More detailed description";
        email = "admin@example.com";
        registration_open = false;
      };

      "Pleroma.Web.Endpoint" = {
        url.host = "fediverse.example.com";
      };
    };
  };
}

Please refer to the configuration cheat sheet for additional configuration options.

User management

After the Akkoma service is running, the administration utility can be used to manage users. In particular an administrative user can be created with

$ pleroma_ctl user new <nickname> <email> --admin --moderator --password <password>

Proxy configuration

Although it is possible to expose Akkoma directly, it is common practice to operate it behind an HTTP reverse proxy such as nginx.

{
  services.akkoma.nginx = {
    enableACME = true;
    forceSSL = true;
  };

  services.nginx = {
    enable = true;

    clientMaxBodySize = "16m";
    recommendedTlsSettings = true;
    recommendedOptimisation = true;
    recommendedGzipSettings = true;
  };
}

Please refer to for details on how to provision an SSL/TLS certificate.

Media proxy

Without the media proxy function, Akkoma does not store any remote media like pictures or video locally, and clients have to fetch them directly from the source server.

{
  # Enable nginx slice module distributed with Tengine
  services.nginx.package = pkgs.tengine;

  # Enable media proxy
  services.akkoma.config.":pleroma".":media_proxy" = {
    enabled = true;
    proxy_opts.redirect_on_failure = true;
  };

  # Adjust the persistent cache size as needed:
  #  Assuming an average object size of 128 KiB, around 1 MiB
  #  of memory is required for the key zone per GiB of cache.
  # Ensure that the cache directory exists and is writable by nginx.
  services.nginx.commonHttpConfig = ''
    proxy_cache_path /var/cache/nginx/cache/akkoma-media-cache
      levels= keys_zone=akkoma_media_cache:16m max_size=16g
      inactive=1y use_temp_path=off;
  '';

  services.akkoma.nginx = {
    locations."/proxy" = {
      proxyPass = "http://unix:/run/akkoma/socket";

      extraConfig = ''
        proxy_cache akkoma_media_cache;

        # Cache objects in slices of 1 MiB
        slice 1m;
        proxy_cache_key $host$uri$is_args$args$slice_range;
        proxy_set_header Range $slice_range;

        # Decouple proxy and upstream responses
        proxy_buffering on;
        proxy_cache_lock on;
        proxy_ignore_client_abort on;

        # Default cache times for various responses
        proxy_cache_valid 200 1y;
        proxy_cache_valid 206 301 304 1h;

        # Allow serving of stale items
        proxy_cache_use_stale error timeout invalid_header updating;
      '';
    };
  };
}

Prefetch remote media

The following example enables the MediaProxyWarmingPolicy MRF policy which automatically fetches all media associated with a post through the media proxy, as soon as the post is received by the instance.

{
  services.akkoma.config.":pleroma".":mrf".policies =
    map (pkgs.formats.elixirConf { }).lib.mkRaw [
      "Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy"
  ];
}

Media previews

Akkoma can generate previews for media.

{
  services.akkoma.config.":pleroma".":media_preview_proxy" = {
    enabled = true;
    thumbnail_max_width = 1920;
    thumbnail_max_height = 1080;
  };
}

Frontend management

Akkoma will be deployed with the akkoma-fe and admin-fe frontends by default. These can be modified by setting {option}services.akkoma.frontends.

The following example overrides the primary frontends default configuration using a custom derivation.

{
  services.akkoma.frontends.primary.package = pkgs.runCommand "akkoma-fe" {
    config = builtins.toJSON {
      expertLevel = 1;
      collapseMessageWithSubject = false;
      stopGifs = false;
      replyVisibility = "following";
      webPushHideIfCW = true;
      hideScopeNotice = true;
      renderMisskeyMarkdown = false;
      hideSiteFavicon = true;
      postContentType = "text/markdown";
      showNavShortcuts = false;
    };
    nativeBuildInputs = with pkgs; [ jq xorg.lndir ];
    passAsFile = [ "config" ];
  } ''
    mkdir $out
    lndir ${pkgs.akkoma-frontends.akkoma-fe} $out

    rm $out/static/config.json
    jq -s add ${pkgs.akkoma-frontends.akkoma-fe}/static/config.json ${config} \
      >$out/static/config.json
  '';
}

Federation policies

Akkoma comes with a number of modules to police federation with other ActivityPub instances. The most valuable for typical users is the :mrf_simple module which allows limiting federation based on instance hostnames.

This configuration snippet provides an example on how these can be used. Choosing an adequate federation policy is not trivial and entails finding a balance between connectivity to the rest of the fediverse and providing a pleasant experience to the users of an instance.

{
  services.akkoma.config.":pleroma" = with (pkgs.formats.elixirConf { }).lib; {
    ":mrf".policies = map mkRaw [
      "Pleroma.Web.ActivityPub.MRF.SimplePolicy"
    ];

    ":mrf_simple" = {
      # Tag all media as sensitive
      media_nsfw = mkMap {
        "nsfw.weird.kinky" = "Untagged NSFW content";
      };

      # Reject all activities except deletes
      reject = mkMap {
        "kiwifarms.cc" = "Persistent harassment of users, no moderation";
      };

      # Force posts to be visible by followers only
      followers_only = mkMap {
        "beta.birdsite.live" = "Avoid polluting timelines with Twitter posts";
      };
    };
  };
}

Upload filters

This example strips GPS and location metadata from uploads, deduplicates them and anonymises the the file name.

{
  services.akkoma.config.":pleroma"."Pleroma.Upload".filters =
    map (pkgs.formats.elixirConf { }).lib.mkRaw [
      "Pleroma.Upload.Filter.Exiftool"
      "Pleroma.Upload.Filter.Dedupe"
      "Pleroma.Upload.Filter.AnonymizeFilename"
    ];
}

Migration from Pleroma

Pleroma instances can be migrated to Akkoma either by copying the database and upload data or by pointing Akkoma to the existing data. The necessary database migrations are run automatically during startup of the service.

The configuration has to be copyedited manually.

Depending on the size of the database, the initial migration may take a long time and exceed the startup timeout of the system manager. To work around this issue one may adjust the startup timeout {option}systemd.services.akkoma.serviceConfig.TimeoutStartSec or simply run the migrations manually:

pleroma_ctl migrate

Copying data

Copying the Pleroma data instead of reusing it in place may permit easier reversion to Pleroma, but allows the two data sets to diverge.

First disable Pleroma and then copy its database and upload data:

# Create a copy of the database
nix-shell -p postgresql --run 'createdb -T pleroma akkoma'

# Copy upload data
mkdir /var/lib/akkoma
cp -R --reflink=auto /var/lib/pleroma/uploads /var/lib/akkoma/

After the data has been copied, enable the Akkoma service and verify that the migration has been successful. If no longer required, the original data may then be deleted:

# Delete original database
nix-shell -p postgresql --run 'dropdb pleroma'

# Delete original Pleroma state
rm -r /var/lib/pleroma

Reusing data

To reuse the Pleroma data in place, disable Pleroma and enable Akkoma, pointing it to the Pleroma database and upload directory.

{
  # Adjust these settings according to the database name and upload directory path used by Pleroma
  services.akkoma.config.":pleroma"."Pleroma.Repo".database = "pleroma";
  services.akkoma.config.":pleroma".":instance".upload_dir = "/var/lib/pleroma/uploads";
}

Please keep in mind that after the Akkoma service has been started, any migrations applied by Akkoma have to be rolled back before the database can be used again with Pleroma. This can be achieved through pleroma_ctl ecto.rollback. Refer to the Ecto SQL documentation for details.

Advanced deployment options

Confinement

The Akkoma systemd service may be confined to a chroot with

{
  services.systemd.akkoma.confinement.enable = true;
}

Confinement of services is not generally supported in NixOS and therefore disabled by default. Depending on the Akkoma configuration, the default confinement settings may be insufficient and lead to subtle errors at run time, requiring adjustment:

Use {option}services.systemd.akkoma.confinement.packages to make packages available in the chroot.

{option}services.systemd.akkoma.serviceConfig.BindPaths and {option}services.systemd.akkoma.serviceConfig.BindReadOnlyPaths permit access to outside paths through bind mounts. Refer to BindPaths= of {manpage}systemd.exec(5) for details.

Distributed deployment

Being an Elixir application, Akkoma can be deployed in a distributed fashion.

This requires setting {option}services.akkoma.dist.address and {option}services.akkoma.dist.cookie. The specifics depend strongly on the deployment environment. For more information please check the relevant Erlang documentation.