1# Akkoma {#module-services-akkoma}
2
3[Akkoma](https://akkoma.dev/) is a lightweight ActivityPub microblogging server forked from Pleroma.
4
5## Service configuration {#modules-services-akkoma-service-configuration}
6
7The Elixir configuration file required by Akkoma is generated automatically from
8[{option}`services.akkoma.config`](options.html#opt-services.akkoma.config). Secrets must be
9included from external files outside of the Nix store by setting the configuration option to
10an attribute set containing the attribute {option}`_secret` – a string pointing to the file
11containing the actual value of the option.
12
13For the mandatory configuration settings these secrets will be generated automatically if the
14referenced file does not exist during startup, unless disabled through
15[{option}`services.akkoma.initSecrets`](options.html#opt-services.akkoma.initSecrets).
16
17The following configuration binds Akkoma to the Unix socket `/run/akkoma/socket`, expecting to
18be run behind a HTTP proxy on `fediverse.example.com`.
19
20
21```nix
22{
23 services.akkoma.enable = true;
24 services.akkoma.config = {
25 ":pleroma" = {
26 ":instance" = {
27 name = "My Akkoma instance";
28 description = "More detailed description";
29 email = "admin@example.com";
30 registration_open = false;
31 };
32
33 "Pleroma.Web.Endpoint" = {
34 url.host = "fediverse.example.com";
35 };
36 };
37 };
38}
39```
40
41Please refer to the [configuration cheat sheet](https://docs.akkoma.dev/stable/configuration/cheatsheet/)
42for additional configuration options.
43
44## User management {#modules-services-akkoma-user-management}
45
46After the Akkoma service is running, the administration utility can be used to
47[manage users](https://docs.akkoma.dev/stable/administration/CLI_tasks/user/). In particular an
48administrative user can be created with
49
50```ShellSession
51$ pleroma_ctl user new <nickname> <email> --admin --moderator --password <password>
52```
53
54## Proxy configuration {#modules-services-akkoma-proxy-configuration}
55
56Although it is possible to expose Akkoma directly, it is common practice to operate it behind an
57HTTP reverse proxy such as nginx.
58
59```nix
60{
61 services.akkoma.nginx = {
62 enableACME = true;
63 forceSSL = true;
64 };
65
66 services.nginx = {
67 enable = true;
68
69 clientMaxBodySize = "16m";
70 recommendedTlsSettings = true;
71 recommendedOptimisation = true;
72 recommendedGzipSettings = true;
73 };
74}
75```
76
77Please refer to [](#module-security-acme) for details on how to provision an SSL/TLS certificate.
78
79### Media proxy {#modules-services-akkoma-media-proxy}
80
81Without the media proxy function, Akkoma does not store any remote media like pictures or video
82locally, and clients have to fetch them directly from the source server.
83
84```nix
85{
86 # Enable nginx slice module distributed with Tengine
87 services.nginx.package = pkgs.tengine;
88
89 # Enable media proxy
90 services.akkoma.config.":pleroma".":media_proxy" = {
91 enabled = true;
92 proxy_opts.redirect_on_failure = true;
93 };
94
95 # Adjust the persistent cache size as needed:
96 # Assuming an average object size of 128 KiB, around 1 MiB
97 # of memory is required for the key zone per GiB of cache.
98 # Ensure that the cache directory exists and is writable by nginx.
99 services.nginx.commonHttpConfig = ''
100 proxy_cache_path /var/cache/nginx/cache/akkoma-media-cache
101 levels= keys_zone=akkoma_media_cache:16m max_size=16g
102 inactive=1y use_temp_path=off;
103 '';
104
105 services.akkoma.nginx = {
106 locations."/proxy" = {
107 proxyPass = "http://unix:/run/akkoma/socket";
108
109 extraConfig = ''
110 proxy_cache akkoma_media_cache;
111
112 # Cache objects in slices of 1 MiB
113 slice 1m;
114 proxy_cache_key $host$uri$is_args$args$slice_range;
115 proxy_set_header Range $slice_range;
116
117 # Decouple proxy and upstream responses
118 proxy_buffering on;
119 proxy_cache_lock on;
120 proxy_ignore_client_abort on;
121
122 # Default cache times for various responses
123 proxy_cache_valid 200 1y;
124 proxy_cache_valid 206 301 304 1h;
125
126 # Allow serving of stale items
127 proxy_cache_use_stale error timeout invalid_header updating;
128 '';
129 };
130 };
131}
132```
133
134#### Prefetch remote media {#modules-services-akkoma-prefetch-remote-media}
135
136The following example enables the `MediaProxyWarmingPolicy` MRF policy which automatically
137fetches all media associated with a post through the media proxy, as soon as the post is
138received by the instance.
139
140```nix
141{
142 services.akkoma.config.":pleroma".":mrf".policies =
143 map (pkgs.formats.elixirConf { }).lib.mkRaw [
144 "Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy"
145 ];
146}
147```
148
149#### Media previews {#modules-services-akkoma-media-previews}
150
151Akkoma can generate previews for media.
152
153```nix
154{
155 services.akkoma.config.":pleroma".":media_preview_proxy" = {
156 enabled = true;
157 thumbnail_max_width = 1920;
158 thumbnail_max_height = 1080;
159 };
160}
161```
162
163## Frontend management {#modules-services-akkoma-frontend-management}
164
165Akkoma will be deployed with the `akkoma-fe` and `admin-fe` frontends by default. These can be
166modified by setting
167[{option}`services.akkoma.frontends`](options.html#opt-services.akkoma.frontends).
168
169The following example overrides the primary frontend’s default configuration using a custom
170derivation.
171
172```nix
173{
174 services.akkoma.frontends.primary.package = pkgs.runCommand "akkoma-fe" {
175 config = builtins.toJSON {
176 expertLevel = 1;
177 collapseMessageWithSubject = false;
178 stopGifs = false;
179 replyVisibility = "following";
180 webPushHideIfCW = true;
181 hideScopeNotice = true;
182 renderMisskeyMarkdown = false;
183 hideSiteFavicon = true;
184 postContentType = "text/markdown";
185 showNavShortcuts = false;
186 };
187 nativeBuildInputs = with pkgs; [ jq xorg.lndir ];
188 passAsFile = [ "config" ];
189 } ''
190 mkdir $out
191 lndir ${pkgs.akkoma-frontends.akkoma-fe} $out
192
193 rm $out/static/config.json
194 jq -s add ${pkgs.akkoma-frontends.akkoma-fe}/static/config.json ${config} \
195 >$out/static/config.json
196 '';
197}
198```
199
200## Federation policies {#modules-services-akkoma-federation-policies}
201
202Akkoma comes with a number of modules to police federation with other ActivityPub instances.
203The most valuable for typical users is the
204[`:mrf_simple`](https://docs.akkoma.dev/stable/configuration/cheatsheet/#mrf_simple) module
205which allows limiting federation based on instance hostnames.
206
207This configuration snippet provides an example on how these can be used. Choosing an adequate
208federation policy is not trivial and entails finding a balance between connectivity to the rest
209of the fediverse and providing a pleasant experience to the users of an instance.
210
211
212```nix
213{
214 services.akkoma.config.":pleroma" = with (pkgs.formats.elixirConf { }).lib; {
215 ":mrf".policies = map mkRaw [
216 "Pleroma.Web.ActivityPub.MRF.SimplePolicy"
217 ];
218
219 ":mrf_simple" = {
220 # Tag all media as sensitive
221 media_nsfw = mkMap {
222 "nsfw.weird.kinky" = "Untagged NSFW content";
223 };
224
225 # Reject all activities except deletes
226 reject = mkMap {
227 "kiwifarms.cc" = "Persistent harassment of users, no moderation";
228 };
229
230 # Force posts to be visible by followers only
231 followers_only = mkMap {
232 "beta.birdsite.live" = "Avoid polluting timelines with Twitter posts";
233 };
234 };
235 };
236}
237```
238
239## Upload filters {#modules-services-akkoma-upload-filters}
240
241This example strips GPS and location metadata from uploads, deduplicates them and anonymises the
242the file name.
243
244```nix
245{
246 services.akkoma.config.":pleroma"."Pleroma.Upload".filters =
247 map (pkgs.formats.elixirConf { }).lib.mkRaw [
248 "Pleroma.Upload.Filter.Exiftool"
249 "Pleroma.Upload.Filter.Dedupe"
250 "Pleroma.Upload.Filter.AnonymizeFilename"
251 ];
252}
253```
254
255## Migration from Pleroma {#modules-services-akkoma-migration-pleroma}
256
257Pleroma instances can be migrated to Akkoma either by copying the database and upload data or by
258pointing Akkoma to the existing data. The necessary database migrations are run automatically
259during startup of the service.
260
261The configuration has to be copy‐edited manually.
262
263Depending on the size of the database, the initial migration may take a long time and exceed the
264startup timeout of the system manager. To work around this issue one may adjust the startup timeout
265{option}`systemd.services.akkoma.serviceConfig.TimeoutStartSec` or simply run the migrations
266manually:
267
268```ShellSession
269pleroma_ctl migrate
270```
271
272### Copying data {#modules-services-akkoma-migration-pleroma-copy}
273
274Copying the Pleroma data instead of re‐using it in place may permit easier reversion to Pleroma,
275but allows the two data sets to diverge.
276
277First disable Pleroma and then copy its database and upload data:
278
279```ShellSession
280# Create a copy of the database
281nix-shell -p postgresql --run 'createdb -T pleroma akkoma'
282
283# Copy upload data
284mkdir /var/lib/akkoma
285cp -R --reflink=auto /var/lib/pleroma/uploads /var/lib/akkoma/
286```
287
288After the data has been copied, enable the Akkoma service and verify that the migration has been
289successful. If no longer required, the original data may then be deleted:
290
291```ShellSession
292# Delete original database
293nix-shell -p postgresql --run 'dropdb pleroma'
294
295# Delete original Pleroma state
296rm -r /var/lib/pleroma
297```
298
299### Re‐using data {#modules-services-akkoma-migration-pleroma-reuse}
300
301To re‐use the Pleroma data in place, disable Pleroma and enable Akkoma, pointing it to the
302Pleroma database and upload directory.
303
304```nix
305{
306 # Adjust these settings according to the database name and upload directory path used by Pleroma
307 services.akkoma.config.":pleroma"."Pleroma.Repo".database = "pleroma";
308 services.akkoma.config.":pleroma".":instance".upload_dir = "/var/lib/pleroma/uploads";
309}
310```
311
312Please keep in mind that after the Akkoma service has been started, any migrations applied by
313Akkoma have to be rolled back before the database can be used again with Pleroma. This can be
314achieved through `pleroma_ctl ecto.rollback`. Refer to the
315[Ecto SQL documentation](https://hexdocs.pm/ecto_sql/Mix.Tasks.Ecto.Rollback.html) for
316details.
317
318## Advanced deployment options {#modules-services-akkoma-advanced-deployment}
319
320### Confinement {#modules-services-akkoma-confinement}
321
322The Akkoma systemd service may be confined to a chroot with
323
324```nix
325{
326 services.systemd.akkoma.confinement.enable = true;
327}
328```
329
330Confinement of services is not generally supported in NixOS and therefore disabled by default.
331Depending on the Akkoma configuration, the default confinement settings may be insufficient and
332lead to subtle errors at run time, requiring adjustment:
333
334Use
335[{option}`services.systemd.akkoma.confinement.packages`](options.html#opt-systemd.services._name_.confinement.packages)
336to make packages available in the chroot.
337
338{option}`services.systemd.akkoma.serviceConfig.BindPaths` and
339{option}`services.systemd.akkoma.serviceConfig.BindReadOnlyPaths` permit access to outside paths
340through bind mounts. Refer to
341[`BindPaths=`](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#BindPaths=)
342of {manpage}`systemd.exec(5)` for details.
343
344### Distributed deployment {#modules-services-akkoma-distributed-deployment}
345
346Being an Elixir application, Akkoma can be deployed in a distributed fashion.
347
348This requires setting
349[{option}`services.akkoma.dist.address`](options.html#opt-services.akkoma.dist.address) and
350[{option}`services.akkoma.dist.cookie`](options.html#opt-services.akkoma.dist.cookie). The
351specifics depend strongly on the deployment environment. For more information please check the
352relevant [Erlang documentation](https://www.erlang.org/doc/reference_manual/distributed.html).