nixos/lemmy: init
Co-authored-by: Raphael Megzari <raphael@megzari.com>
This commit is contained in:
parent
8a896d686d
commit
cc3b147ed1
5 changed files with 331 additions and 1 deletions
|
@ -985,6 +985,7 @@
|
|||
./services/web-apps/jirafeau.nix
|
||||
./services/web-apps/jitsi-meet.nix
|
||||
./services/web-apps/keycloak.nix
|
||||
./services/web-apps/lemmy.nix
|
||||
./services/web-apps/limesurvey.nix
|
||||
./services/web-apps/mastodon.nix
|
||||
./services/web-apps/mattermost.nix
|
||||
|
|
34
nixos/modules/services/web-apps/lemmy.md
Normal file
34
nixos/modules/services/web-apps/lemmy.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Lemmy {#module-services-lemmy}
|
||||
|
||||
Lemmy is a federated alternative to reddit in rust.
|
||||
|
||||
## Quickstart {#module-services-lemmy-quickstart}
|
||||
|
||||
the minimum to start lemmy is
|
||||
|
||||
```nix
|
||||
services.lemmy = {
|
||||
enable = true;
|
||||
settings = {
|
||||
hostname = "lemmy.union.rocks";
|
||||
database.createLocally = true;
|
||||
};
|
||||
jwtSecretPath = "/run/secrets/lemmyJwt";
|
||||
caddy.enable = true;
|
||||
}
|
||||
```
|
||||
|
||||
(note that you can use something like agenix to get your secret jwt to the specified path)
|
||||
|
||||
this will start the backend on port 8536 and the frontend on port 1234.
|
||||
It will expose your instance with a caddy reverse proxy to the hostname you've provided.
|
||||
Postgres will be initialized on that same instance automatically.
|
||||
|
||||
## Usage {#module-services-lemmy-usage}
|
||||
|
||||
On first connection you will be asked to define an admin user.
|
||||
|
||||
## Missing {#module-services-lemmy-missing}
|
||||
|
||||
- Exposing with nginx is not implemented yet.
|
||||
- This has been tested using a local database with a unix socket connection. Using different database settings will likely require modifications
|
238
nixos/modules/services/web-apps/lemmy.nix
Normal file
238
nixos/modules/services/web-apps/lemmy.nix
Normal file
|
@ -0,0 +1,238 @@
|
|||
{ lib, pkgs, config, ... }:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.services.lemmy;
|
||||
settingsFormat = pkgs.formats.json { };
|
||||
in
|
||||
{
|
||||
meta.maintainers = with maintainers; [ happysalada ];
|
||||
# Don't edit the docbook xml directly, edit the md and generate it:
|
||||
# `pandoc lemmy.md -t docbook --top-level-division=chapter --extract-media=media -f markdown+smart > lemmy.xml`
|
||||
meta.doc = ./lemmy.xml;
|
||||
|
||||
options.services.lemmy = {
|
||||
|
||||
enable = mkEnableOption "lemmy a federated alternative to reddit in rust";
|
||||
|
||||
jwtSecretPath = mkOption {
|
||||
type = types.path;
|
||||
description = "Path to read the jwt secret from.";
|
||||
};
|
||||
|
||||
ui = {
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 1234;
|
||||
description = "Port where lemmy-ui should listen for incoming requests.";
|
||||
};
|
||||
};
|
||||
|
||||
caddy.enable = mkEnableOption "exposing lemmy with the caddy reverse proxy";
|
||||
|
||||
settings = mkOption {
|
||||
default = { };
|
||||
description = "Lemmy configuration";
|
||||
|
||||
type = types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
|
||||
options.hostname = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
description = "The domain name of your instance (eg 'lemmy.ml').";
|
||||
};
|
||||
|
||||
options.port = mkOption {
|
||||
type = types.port;
|
||||
default = 8536;
|
||||
description = "Port where lemmy should listen for incoming requests.";
|
||||
};
|
||||
|
||||
options.federation = {
|
||||
enabled = mkEnableOption "activitypub federation";
|
||||
};
|
||||
|
||||
options.captcha = {
|
||||
enabled = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Enable Captcha.";
|
||||
};
|
||||
difficulty = mkOption {
|
||||
type = types.enum [ "easy" "medium" "hard" ];
|
||||
default = "medium";
|
||||
description = "The difficultly of the captcha to solve.";
|
||||
};
|
||||
};
|
||||
|
||||
options.database.createLocally = mkEnableOption "creation of database on the instance";
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
localPostgres = (cfg.settings.database.host == "localhost" || cfg.settings.database.host == "/run/postgresql");
|
||||
in
|
||||
lib.mkIf cfg.enable {
|
||||
services.lemmy.settings = (mapAttrs (name: mkDefault)
|
||||
{
|
||||
bind = "127.0.0.1";
|
||||
tls_enabled = true;
|
||||
pictrs_url = with config.services.pict-rs; "http://${address}:${toString port}";
|
||||
actor_name_max_length = 20;
|
||||
|
||||
rate_limit.message = 180;
|
||||
rate_limit.message_per_second = 60;
|
||||
rate_limit.post = 6;
|
||||
rate_limit.post_per_second = 600;
|
||||
rate_limit.register = 3;
|
||||
rate_limit.register_per_second = 3600;
|
||||
rate_limit.image = 6;
|
||||
rate_limit.image_per_second = 3600;
|
||||
} // {
|
||||
database = mapAttrs (name: mkDefault) {
|
||||
user = "lemmy";
|
||||
host = "/run/postgresql";
|
||||
port = 5432;
|
||||
database = "lemmy";
|
||||
pool_size = 5;
|
||||
};
|
||||
});
|
||||
|
||||
services.postgresql = mkIf localPostgres {
|
||||
enable = mkDefault true;
|
||||
};
|
||||
|
||||
services.pict-rs.enable = true;
|
||||
|
||||
services.caddy = mkIf cfg.caddy.enable {
|
||||
enable = mkDefault true;
|
||||
virtualHosts."${cfg.settings.hostname}" = {
|
||||
extraConfig = ''
|
||||
handle_path /static/* {
|
||||
root * ${pkgs.lemmy-ui}/dist
|
||||
file_server
|
||||
}
|
||||
@for_backend {
|
||||
path /api/* /pictrs/* feeds/* nodeinfo/*
|
||||
}
|
||||
handle @for_backend {
|
||||
reverse_proxy 127.0.0.1:${toString cfg.settings.port}
|
||||
}
|
||||
@post {
|
||||
method POST
|
||||
}
|
||||
handle @post {
|
||||
reverse_proxy 127.0.0.1:${toString cfg.settings.port}
|
||||
}
|
||||
@jsonld {
|
||||
header Accept "application/activity+json"
|
||||
header Accept "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
|
||||
}
|
||||
handle @jsonld {
|
||||
reverse_proxy 127.0.0.1:${toString cfg.settings.port}
|
||||
}
|
||||
handle {
|
||||
reverse_proxy 127.0.0.1:${toString cfg.ui.port}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
assertions = [{
|
||||
assertion = cfg.settings.database.createLocally -> localPostgres;
|
||||
message = "if you want to create the database locally, you need to use a local database";
|
||||
}];
|
||||
|
||||
systemd.services.lemmy = {
|
||||
description = "Lemmy server";
|
||||
|
||||
environment = {
|
||||
LEMMY_CONFIG_LOCATION = "/run/lemmy/config.hjson";
|
||||
|
||||
# Verify how this is used, and don't put the password in the nix store
|
||||
LEMMY_DATABASE_URL = with cfg.settings.database;"postgres:///${database}?host=${host}";
|
||||
};
|
||||
|
||||
documentation = [
|
||||
"https://join-lemmy.org/docs/en/administration/from_scratch.html"
|
||||
"https://join-lemmy.org/docs"
|
||||
];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
after = [ "pict-rs.service " ] ++ lib.optionals cfg.settings.database.createLocally [ "lemmy-postgresql.service" ];
|
||||
|
||||
requires = lib.optionals cfg.settings.database.createLocally [ "lemmy-postgresql.service" ];
|
||||
|
||||
# script is needed here since loadcredential is not accessible on ExecPreStart
|
||||
script = ''
|
||||
${pkgs.coreutils}/bin/install -m 600 ${settingsFormat.generate "config.hjson" cfg.settings} /run/lemmy/config.hjson
|
||||
jwtSecret="$(< $CREDENTIALS_DIRECTORY/jwt_secret )"
|
||||
${pkgs.jq}/bin/jq ".jwt_secret = \"$jwtSecret\"" /run/lemmy/config.hjson | ${pkgs.moreutils}/bin/sponge /run/lemmy/config.hjson
|
||||
${pkgs.lemmy-server}/bin/lemmy_server
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
RuntimeDirectory = "lemmy";
|
||||
LoadCredential = "jwt_secret:${cfg.jwtSecretPath}";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.lemmy-ui = {
|
||||
description = "Lemmy ui";
|
||||
|
||||
environment = {
|
||||
LEMMY_UI_HOST = "127.0.0.1:${toString cfg.ui.port}";
|
||||
LEMMY_INTERNAL_HOST = "127.0.0.1:${toString cfg.settings.port}";
|
||||
LEMMY_EXTERNAL_HOST = cfg.settings.hostname;
|
||||
LEMMY_HTTPS = "false";
|
||||
};
|
||||
|
||||
documentation = [
|
||||
"https://join-lemmy.org/docs/en/administration/from_scratch.html"
|
||||
"https://join-lemmy.org/docs"
|
||||
];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
after = [ "lemmy.service" ];
|
||||
|
||||
requires = [ "lemmy.service" ];
|
||||
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
WorkingDirectory = "${pkgs.lemmy-ui}";
|
||||
ExecStart = "${pkgs.nodejs}/bin/node ${pkgs.lemmy-ui}/dist/js/server.js";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.lemmy-postgresql = mkIf cfg.settings.database.createLocally {
|
||||
description = "Lemmy postgresql db";
|
||||
after = [ "postgresql.service" ];
|
||||
bindsTo = [ "postgresql.service" ];
|
||||
requiredBy = [ "lemmy.service" ];
|
||||
partOf = [ "lemmy.service" ];
|
||||
script = with cfg.settings.database; ''
|
||||
PSQL() {
|
||||
${config.services.postgresql.package}/bin/psql --port=${toString cfg.settings.database.port} "$@"
|
||||
}
|
||||
# check if the database already exists
|
||||
if ! PSQL -lqt | ${pkgs.coreutils}/bin/cut -d \| -f 1 | ${pkgs.gnugrep}/bin/grep -qw ${database} ; then
|
||||
PSQL -tAc "CREATE ROLE ${user} WITH LOGIN;"
|
||||
PSQL -tAc "CREATE DATABASE ${database} WITH OWNER ${user};"
|
||||
fi
|
||||
'';
|
||||
serviceConfig = {
|
||||
User = config.services.postgresql.superUser;
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
56
nixos/modules/services/web-apps/lemmy.xml
Normal file
56
nixos/modules/services/web-apps/lemmy.xml
Normal file
|
@ -0,0 +1,56 @@
|
|||
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="module-services-lemmy">
|
||||
<title>Lemmy</title>
|
||||
<para>
|
||||
Lemmy is a federated alternative to reddit in rust.
|
||||
</para>
|
||||
<section xml:id="module-services-lemmy-quickstart">
|
||||
<title>Quickstart</title>
|
||||
<para>
|
||||
the minimum to start lemmy is
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
services.lemmy = {
|
||||
enable = true;
|
||||
settings = {
|
||||
hostname = "lemmy.union.rocks";
|
||||
database.createLocally = true;
|
||||
};
|
||||
jwtSecretPath = "/run/secrets/lemmyJwt";
|
||||
caddy.enable = true;
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
(note that you can use something like agenix to get your secret
|
||||
jwt to the specified path)
|
||||
</para>
|
||||
<para>
|
||||
this will start the backend on port 8536 and the frontend on port
|
||||
1234. It will expose your instance with a caddy reverse proxy to
|
||||
the hostname you’ve provided. Postgres will be initialized on that
|
||||
same instance automatically.
|
||||
</para>
|
||||
</section>
|
||||
<section xml:id="module-services-lemmy-usage">
|
||||
<title>Usage</title>
|
||||
<para>
|
||||
On first connection you will be asked to define an admin user.
|
||||
</para>
|
||||
</section>
|
||||
<section xml:id="module-services-lemmy-missing">
|
||||
<title>Missing</title>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
Exposing with nginx is not implemented yet.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
This has been tested using a local database with a unix socket
|
||||
connection. Using different database settings will likely
|
||||
require modifications
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</chapter>
|
|
@ -57,7 +57,8 @@ mkYarnPackage {
|
|||
|
||||
preInstall = ''
|
||||
mkdir $out
|
||||
cp -R ./deps/lemmy-ui/dist/assets $out
|
||||
cp -R ./deps/lemmy-ui/dist $out
|
||||
cp -R ./node_modules $out
|
||||
'';
|
||||
|
||||
distPhase = "true";
|
||||
|
|
Loading…
Reference in a new issue