{ lib, pkgs, config, myconfig, mylibs, ... }:
let
etherpad = pkgs.webapps.etherpad-lite.withModules
(builtins.attrValues pkgs.webapps.etherpad-lite-modules);
env = myconfig.env.tools.etherpad-lite;
varDir = etherpad.varDir;
cfg = config.services.myWebsites.tools.etherpad-lite;
# Make sure we’re not rebuilding whole libreoffice just because of a
# dependency
libreoffice = (import <nixpkgs> { overlays = []; }).libreoffice-fresh;
in {
options.services.myWebsites.tools.etherpad-lite = {
enable = lib.mkEnableOption "enable etherpad's website";
};
config = lib.mkIf cfg.enable {
mySecrets.keys = [
{
dest = "webapps/tools-etherpad-apikey";
permissions = "0400";
text = env.api_key;
}
{
dest = "webapps/tools-etherpad-sessionkey";
permissions = "0400";
text = env.session_key;
}
{
dest = "webapps/tools-etherpad";
permissions = "0400";
text = ''
{
"title": "Etherpad",
"favicon": "favicon.ico",
"ip": "127.0.0.1",
"port" : ${env.listenPort},
"showSettingsInAdminPage" : false,
"dbType" : "postgres",
"dbSettings" : {
"user" : "${env.postgresql.user}",
"host" : "${env.postgresql.socket}",
"password": "${env.postgresql.password}",
"database": "${env.postgresql.database}",
"charset" : "utf8mb4"
},
"defaultPadText" : "Welcome to Etherpad!\n\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!\n\nGet involved with Etherpad at http:\/\/etherpad.org\n",
"padOptions": {
"noColors": false,
"showControls": true,
"showChat": true,
"showLineNumbers": true,
"useMonospaceFont": false,
"userName": false,
"userColor": false,
"rtl": false,
"alwaysShowChat": false,
"chatAndUsers": false,
"lang": "en-gb"
},
"suppressErrorsInPadText" : false,
"requireSession" : false,
"editOnly" : false,
"sessionNoPassword" : false,
"minify" : true,
"maxAge" : 21600,
"abiword" : null,
"soffice" : "${libreoffice}/bin/soffice",
"tidyHtml" : "${pkgs.html-tidy}/bin/tidy",
"allowUnknownFileEnds" : true,
"requireAuthentication" : false,
"requireAuthorization" : false,
"trustProxy" : false,
"disableIPlogging" : false,
"automaticReconnectionTimeout" : 0,
"scrollWhenFocusLineIsOutOfViewport": {
"percentage": {
"editionAboveViewport": 0,
"editionBelowViewport": 0
},
"duration": 0,
"scrollWhenCaretIsInTheLastLineOfViewport": false,
"percentageToScrollWhenUserPressesArrowUp": 0
},
"users": {
"ldapauth": {
"url": "ldaps://${env.ldap.host}",
"accountBase": "${env.ldap.base}",
"accountPattern": "(&(memberOf=cn=users,cn=etherpad,ou=services,dc=immae,dc=eu)(uid={{username}}))",
"displayNameAttribute": "cn",
"searchDN": "cn=etherpad,ou=services,dc=immae,dc=eu",
"searchPWD": "${env.ldap.password}",
"groupSearchBase": "${env.ldap.base}",
"groupAttribute": "member",
"groupAttributeIsDN": true,
"searchScope": "sub",
"groupSearch": "(memberOf=cn=groups,cn=etherpad,ou=services,dc=immae,dc=eu)",
"anonymousReadonly": false
}
},
"socketTransportProtocols" : ["xhr-polling", "jsonp-polling", "htmlfile"],
"loadTest": false,
"indentationOnNewLine": false,
"toolbar": {
"left": [
["bold", "italic", "underline", "strikethrough"],
["orderedlist", "unorderedlist", "indent", "outdent"],
["undo", "redo"],
["clearauthorship"]
],
"right": [
["importexport", "timeslider", "savedrevision"],
["settings", "embed"],
["showusers"]
],
"timeslider": [
["timeslider_export", "timeslider_returnToPad"]
]
},
"loglevel": "INFO",
"logconfig" : { "appenders": [ { "type": "console" } ] }
}
'';
}
];
systemd.services.etherpad-lite = {
description = "Etherpad-lite";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" "postgresql.service" ];
wants = [ "postgresql.service" ];
environment.NODE_ENV = "production";
environment.HOME = etherpad;
path = [ pkgs.nodejs ];
script = ''
exec ${pkgs.nodejs}/bin/node ${etherpad}/src/node/server.js \
--sessionkey /var/secrets/webapps/tools-etherpad-sessionkey \
--apikey /var/secrets/webapps/tools-etherpad-apikey \
--settings /var/secrets/webapps/tools-etherpad
'';
serviceConfig = {
DynamicUser = true;
User = "etherpad-lite";
Group = "etherpad-lite";
SupplementaryGroups = "keys";
WorkingDirectory = etherpad;
PrivateTmp = true;
NoNewPrivileges = true;
PrivateDevices = true;
ProtectHome = true;
ProtectControlGroups = true;
ProtectKernelModules = true;
Restart = "always";
Type = "simple";
TimeoutSec = 60;
# Use ReadWritePaths= instead if varDir is outside of /var/lib
StateDirectory="etherpad-lite";
ExecStartPre = [
"+${pkgs.coreutils}/bin/install -d -m 0755 -o etherpad-lite -g etherpad-lite ${varDir}/ep_initialized"
"+${pkgs.coreutils}/bin/chown -R etherpad-lite:etherpad-lite ${varDir} /var/secrets/webapps/tools-etherpad /var/secrets/webapps/tools-etherpad-sessionkey /var/secrets/webapps/tools-etherpad-apikey"
];
};
};
services.myWebsites.tools.modules = [
"headers" "proxy" "proxy_http" "proxy_wstunnel"
];
security.acme.certs."eldiron".extraDomains."ether.immae.eu" = null;
services.myWebsites.tools.vhostConfs.etherpad-lite = {
certName = "eldiron";
hosts = [ "ether.immae.eu" ];
root = null;
extraConfig = [ ''
Header always set Strict-Transport-Security "max-age=31536000; includeSubdomains;"
RequestHeader set X-Forwarded-Proto "https"
RewriteEngine On
RewriteMap redirects "txt:${pkgs.writeText "redirects.txt" myconfig.env.tools.etherpad-lite.redirects}"
RewriteCond %{QUERY_STRING} "!noredirect"
RewriteCond %{REQUEST_URI} "^(.*)$"
RewriteCond ''${redirects:$1|Unknown} "!Unknown"
RewriteRule "^(.*)$" ''${redirects:$1} [L,NE,R=301,QSD]
RewriteCond %{REQUEST_URI} ^/socket.io [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule /(.*) ws://localhost:${env.listenPort}/$1 [P,L]
<IfModule mod_proxy.c>
ProxyVia On
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://localhost:${env.listenPort}/
ProxyPassReverse / http://localhost:${env.listenPort}/
<Proxy *>
Options FollowSymLinks MultiViews
AllowOverride None
Require all granted
</Proxy>
</IfModule>
'' ];
};
};
}