Compare commits

...

2 Commits

Author SHA1 Message Date
Félix Baylac-Jacqué 00d108de62
nixos/pleroma: add pleroma NixOS module
This module is not trying to configure either postgresql nor nginx.
It's is a design decision, not an omission. A webserver setup can be
highly complex.

The idea is trying not to be smarter than the user, providing them
with a simple tool. They are smart enough to figure the interaction
between the various component by themselves!

The module has one and only job: setting up a pleroma service.
2020-09-27 00:59:00 +02:00
Félix Baylac-Jacqué 0122f75747
Update readme 2020-09-27 00:59:00 +02:00
2 changed files with 227 additions and 4 deletions

91
modules/pleroma.nix Normal file
View File

@ -0,0 +1,91 @@
{ config, options, lib, pkgs, stdenv, ... }:
let
cfg = config.services.pleroma;
in {
options = {
services.pleroma = with lib; {
enable = mkEnableOption "pleroma";
package = mkOption {
type = types.package;
default = import ../default.nix { inherit pkgs; };
description = "Pleroma package to use.";
};
user = mkOption {
type = types.str;
default = "pleroma";
description = "User account under which pleroma runs.";
};
group = mkOption {
type = types.str;
default = "pleroma";
description = "Group account under which pleroma runs.";
};
};
};
config = lib.mkIf cfg.enable {
users = {
users."${cfg.user}" = {
description = "Pleroma user";
home = "/var/lib/pleroma";
extraGroups = [ cfg.group ];
};
groups."${cfg.group}" = {};
};
environment.systemPackages = [ cfg.package ];
systemd.services.pleroma = {
description = "Pleroma social network";
after = [ "network-online.target" "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
environment = {
MIX_ENV = "prod";
};
serviceConfig = {
User = cfg.user;
Group = cfg.group;
Type = "forking";
WorkingDirectory = "/var/lib/pleroma";
StateDirectory = "pleroma pleroma/static pleroma/uploads";
StateDirectoryMode = "700";
# Checking the conf file is there then running the database
# migration before each service start, just in case there are
# some pending ones.
#
# It's sub-optimal as we'll always run this, even if pleroma
# has not been updated. But the no-op process is pretty fast.
# Better be safe than sorry migration-wise.
ExecStartPre =
let preScript = pkgs.writers.writeBashBin "pleromaStartPre" ''
if [ ! -f "/etc/pleroma/config.exs" ]; then
echo "ERROR: Missing pleroma config file at /etc/pleroma/config.exs"
echo "Did you read https://git.alternativebit.fr/NinjaTrappeur/pleroma-otp-nixos/src/branch/master/readme.md#user-content-pleroma-configuration-management ?"
exit 1
fi
${cfg.package}/bin/pleroma_ctl migrate'';
in "${preScript}/bin/pleromaStartPre";
ExecStart = "${cfg.package}/bin/pleroma daemon";
ExecStop = "${cfg.package}/bin/pleroma stop";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
# Systemd sandboxing directives.
# Taken from the upstream contrib systemd service at
# pleroma/installation/pleroma.service
PrivateTmp = true;
ProtectHome = true;
ProtectSystem = "full";
PrivateDevices = false;
NoNewPrivileges = true;
CapabilityBoundingSet = "~CAP_SYS_ADMIN";
};
};
};
meta.maintainers = with lib.maintainers; [ ninjatrappeur ];
}

140
readme.md
View File

@ -1,12 +1,144 @@
# Pleroma on NixOS: OTP Release
## TODO
## Quick Start
- Add NixOS module.
Add your pleroma configuration to `/etc/pleroma/config.exs`, make sure
it's readable by the `pleroma` user.
## Minor Annoyances
You can then use the following example to get started.
We're retrieving the binary distribution directly from the GitLab CI pipeline.
```
{ pkgs, ... }:
let
pleromaModuleSrc = builtins.fetchTarball {
url = "https://git.alternativebit.fr/NinjaTrappeur/pleroma-otp-nixos/archive/master.tar.gz";
sha256 = "0000000000000000000000000000000000000000000000000000";
};
in
{
imports = [ "${pleromaModuleSrc}/modules/pleroma.nix" ]
security.acme = {
email = "root@tld";
acceptTerms = true;
certs = {
"social.tld.com" = {
webroot = "/var/www/social.tld.com";
email = "root@tld";
group = "nginx";
};
};
};
services = {
pleroma.enable = true;
postgresql = {
enable = true;
package = pkgs.postgresql_12;
};
nginx = {
enable = true;
virtualHosts."social.tld.com" = {
addSSL = true;
sslCertificate = "/var/lib/acme/social.tld.com/fullchain.pem";
sslCertificateKey = "/var/lib/acme/social.tld.com/key.pem";
root = "/var/www/social.tld.com";
# ACME endpoint
locations."/.well-known/acme-challenge" = {
root = "/var/www/social.tld.com/";
};
locations."/" = {
proxyPass = "http://localhost:4000";
extraConfig = ''
# if you do not want remote frontends to be able to access your Pleroma backend
# server, remove these lines.
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
if ($request_method = OPTIONS) {
return 204;
}
# stop removing lines here.
add_header X-XSS-Protection "1; mode=block";
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Referrer-Policy same-origin;
add_header X-Download-Options noopen;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
client_max_body_size 16m;
'';
};
};
};
};
}
```
## Pleroma Configuration Management
### File Configuration
Pleroma is expecting its configuration to be found at
`/etc/pleroma/config.exs`. This configuration file is containing some
secrets, the Nix store being world-readable, it seems like storing the
pleroma conf there is a pretty bad idea.
Meaning, this module won't handle this configuration file for you, you
have to do it manually. From here, two options:
1. You are migrating a src-based install (mix-based). You can re-use
your `$src_root/config/prod.secret.exs` file. Change the `use Mix.Config`
statement with `use Config`.
2. This is a brand new installation. In that case you can use
`pleroma_ctl instance gen --output config.exs --output-psql setup.psql`,
this will prompt you some questions and will generate both your
config file and database initial migration. Note: `pleroma_ctl`
will be in your system path as soon as you enable the pleroma
service. You can alternatively build it by building this repo's
`default.nix` derivation.
### Database Configuration
If it's not already done, you need to seed your pleroma postgresql database.
Using the `setup.psql` file generated in the previous section, you can
load the seed with `sudo -u postgres psql -f seed.psql`.
## Open Questions
- In this module, we decided not to try any kind of magical conf on
the Nginx-side. Web server configurations can quickly get pretty
custom, letting the admin handle it seems like the best thing to do
to me. On top of that, a lot of directives we're using are not
covered by the NixOS Nginx module, we have to make a heavy use of
`extraConfig`, making the whole config not easily overrideable.
**However**, the Nginx block config is quite huge, there's maybe
something smarter to do.
- The configuration file contains some secrets. On top of that, the
config file format is a pure Elixir file, making it poor candidate
for a
[RFC042](https://github.com/Infinisil/rfcs/blob/config-option/rfcs/0042-config-option.md)
-style `settings` attributeset. Because of that, I kinda chicken out
and decided to keep the conf file management 100% out of this
module. There's probably a better middle ground here. Something
allowing us to keep the secret part (db password, endpoint secret
key) out of the store while leveraging the module system for the
less secret configuration settings. Maybe the solution is to
leverage Elixir's import system?
## Update Pleroma to a New Version
We're retrieving the binary distribution directly from the GitLab CI
pipeline.
To find the latest and greatest bindist stable URL, you have to visit
https://git.pleroma.social/pleroma/pleroma/-/tree/stable, clicky click