Merge pull request #16132 from zohl/tt-rss

tt-rss service: init at 16.3

Changed files
+647 -22
nixos
modules
services
web-apps
web-servers
pkgs
servers
tt-rss
top-level
+2 -1
nixos/modules/module-list.nix
···
./services/ttys/gpm.nix
./services/ttys/kmscon.nix
./services/web-apps/pump.io.nix
+
./services/web-apps/tt-rss.nix
./services/web-servers/apache-httpd/default.nix
./services/web-servers/caddy.nix
./services/web-servers/fcgiwrap.nix
···
./services/web-servers/lighttpd/gitweb.nix
./services/web-servers/lighttpd/inginious.nix
./services/web-servers/nginx/default.nix
-
./services/web-servers/phpfpm.nix
+
./services/web-servers/phpfpm/default.nix
./services/web-servers/shellinabox.nix
./services/web-servers/tomcat.nix
./services/web-servers/uwsgi.nix
+567
nixos/modules/services/web-apps/tt-rss.nix
···
+
{ config, lib, pkgs, ... }:
+
+
with lib;
+
let
+
cfg = config.services.tt-rss;
+
+
configVersion = 26;
+
+
boolToString = b: if b then "true" else "false";
+
+
cacheDir = "cache";
+
lockDir = "lock";
+
feedIconsDir = "feed-icons";
+
+
dbPort = if cfg.database.port == null
+
then (if cfg.database.type == "pgsql" then 5432 else 3306)
+
else cfg.database.port;
+
+
poolName = "tt-rss";
+
virtualHostName = "tt-rss";
+
+
tt-rss-config = pkgs.writeText "config.php" ''
+
<?php
+
+
define('PHP_EXECUTABLE', '${pkgs.php}/bin/php');
+
+
define('LOCK_DIRECTORY', '${lockDir}');
+
define('CACHE_DIR', '${cacheDir}');
+
define('ICONS_DIR', '${feedIconsDir}');
+
define('ICONS_URL', '${feedIconsDir}');
+
define('SELF_URL_PATH', '${cfg.selfUrlPath}');
+
+
define('MYSQL_CHARSET', 'UTF8');
+
+
define('DB_TYPE', '${cfg.database.type}');
+
define('DB_HOST', '${cfg.database.host}');
+
define('DB_USER', '${cfg.database.user}');
+
define('DB_NAME', '${cfg.database.name}');
+
define('DB_PASS', '${escape ["'" "\\"] cfg.database.password}');
+
define('DB_PORT', '${toString dbPort}');
+
+
define('AUTH_AUTO_CREATE', ${boolToString cfg.auth.autoCreate});
+
define('AUTH_AUTO_LOGIN', ${boolToString cfg.auth.autoLogin});
+
+
define('FEED_CRYPT_KEY', '${escape ["'" "\\"] cfg.feedCryptKey}');
+
+
+
define('SINGLE_USER_MODE', ${boolToString cfg.singleUserMode});
+
+
define('SIMPLE_UPDATE_MODE', ${boolToString cfg.simpleUpdateMode});
+
define('CHECK_FOR_UPDATES', ${boolToString cfg.checkForUpdates});
+
+
define('FORCE_ARTICLE_PURGE', ${toString cfg.forceArticlePurge});
+
define('SESSION_COOKIE_LIFETIME', ${toString cfg.sessionCookieLifetime});
+
define('ENABLE_GZIP_OUTPUT', ${boolToString cfg.enableGZipOutput});
+
+
define('PLUGINS', '${builtins.concatStringsSep "," cfg.plugins}');
+
+
define('LOG_DESTINATION', '${cfg.logDestination}');
+
define('CONFIG_VERSION', ${toString configVersion});
+
+
+
define('PUBSUBHUBBUB_ENABLED', ${boolToString cfg.pubSubHubbub.enable});
+
define('PUBSUBHUBBUB_HUB', '${cfg.pubSubHubbub.hub}');
+
+
define('SPHINX_SERVER', '${cfg.sphinx.server}');
+
define('SPHINX_INDEX', '${builtins.concatStringsSep "," cfg.sphinx.index}');
+
+
define('ENABLE_REGISTRATION', ${boolToString cfg.registration.enable});
+
define('REG_NOTIFY_ADDRESS', '${cfg.registration.notifyAddress}');
+
define('REG_MAX_USERS', ${toString cfg.registration.maxUsers});
+
+
define('SMTP_SERVER', '${cfg.email.server}');
+
define('SMTP_LOGIN', '${cfg.email.login}');
+
define('SMTP_PASSWORD', '${escape ["'" "\\"] cfg.email.password}');
+
define('SMTP_SECURE', '${cfg.email.security}');
+
+
define('SMTP_FROM_NAME', '${escape ["'" "\\"] cfg.email.fromName}');
+
define('SMTP_FROM_ADDRESS', '${escape ["'" "\\"] cfg.email.fromAddress}');
+
define('DIGEST_SUBJECT', '${escape ["'" "\\"] cfg.email.digestSubject}');
+
'';
+
+
in {
+
+
###### interface
+
+
options = {
+
+
services.tt-rss = {
+
+
enable = mkEnableOption "tt-rss";
+
+
user = mkOption {
+
type = types.str;
+
default = "nginx";
+
example = "nginx";
+
description = ''
+
User account under which both the service and the web-application run.
+
'';
+
};
+
+
pool = mkOption {
+
type = types.str;
+
default = "${poolName}";
+
description = ''
+
Name of existing phpfpm pool that is used to run web-application.
+
If not specified a pool will be created automatically with
+
default values.
+
'';
+
};
+
+
virtualHost = mkOption {
+
type = types.str;
+
default = "${virtualHostName}";
+
description = ''
+
Name of existing nginx virtual host that is used to run web-application.
+
If not specified a host will be created automatically with
+
default values.
+
'';
+
};
+
+
database = {
+
type = mkOption {
+
type = types.enum ["pgsql" "mysql"];
+
default = "pgsql";
+
description = ''
+
Database to store feeds. Supported are pgsql and mysql.
+
'';
+
};
+
+
host = mkOption {
+
type = types.str;
+
default = "localhost";
+
description = ''
+
Host of the database.
+
'';
+
};
+
+
name = mkOption {
+
type = types.str;
+
default = "tt_rss";
+
description = ''
+
Name of the existing database.
+
'';
+
};
+
+
user = mkOption {
+
type = types.str;
+
default = "tt_rss";
+
description = ''
+
The database user. The user must exist and has access to
+
the specified database.
+
'';
+
};
+
+
password = mkOption {
+
type = types.nullOr types.str;
+
default = null;
+
description = ''
+
The database user's password.
+
'';
+
};
+
+
port = mkOption {
+
type = types.nullOr types.int;
+
default = null;
+
description = ''
+
The database's port. If not set, the default ports will be provided (5432
+
and 3306 for pgsql and mysql respectively).
+
'';
+
};
+
};
+
+
auth = {
+
autoCreate = mkOption {
+
type = types.bool;
+
default = true;
+
description = ''
+
Allow authentication modules to auto-create users in tt-rss internal
+
database when authenticated successfully.
+
'';
+
};
+
+
autoLogin = mkOption {
+
type = types.bool;
+
default = true;
+
description = ''
+
Automatically login user on remote or other kind of externally supplied
+
authentication, otherwise redirect to login form as normal.
+
If set to true, users won't be able to set application language
+
and settings profile.
+
'';
+
};
+
};
+
+
pubSubHubbub = {
+
hub = mkOption {
+
type = types.str;
+
default = "";
+
description = ''
+
URL to a PubSubHubbub-compatible hub server. If defined, "Published
+
articles" generated feed would automatically become PUSH-enabled.
+
'';
+
};
+
+
enable = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
Enable client PubSubHubbub support in tt-rss. When disabled, tt-rss
+
won't try to subscribe to PUSH feed updates.
+
'';
+
};
+
};
+
+
sphinx = {
+
server = mkOption {
+
type = types.str;
+
default = "localhost:9312";
+
description = ''
+
Hostname:port combination for the Sphinx server.
+
'';
+
};
+
+
index = mkOption {
+
type = types.listOf types.str;
+
default = ["ttrss" "delta"];
+
description = ''
+
Index names in Sphinx configuration. Example configuration
+
files are available on tt-rss wiki.
+
'';
+
};
+
};
+
+
registration = {
+
enable = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
Allow users to register themselves. Please be aware that allowing
+
random people to access your tt-rss installation is a security risk
+
and potentially might lead to data loss or server exploit. Disabled
+
by default.
+
'';
+
};
+
+
notifyAddress = mkOption {
+
type = types.str;
+
default = "";
+
description = ''
+
Email address to send new user notifications to.
+
'';
+
};
+
+
maxUsers = mkOption {
+
type = types.int;
+
default = 0;
+
description = ''
+
Maximum amount of users which will be allowed to register on this
+
system. 0 - no limit.
+
'';
+
};
+
};
+
+
email = {
+
server = mkOption {
+
type = types.str;
+
default = "";
+
example = "localhost:25";
+
description = ''
+
Hostname:port combination to send outgoing mail. Blank - use system
+
MTA.
+
'';
+
};
+
+
login = mkOption {
+
type = types.str;
+
default = "";
+
description = ''
+
SMTP authentication login used when sending outgoing mail.
+
'';
+
};
+
+
password = mkOption {
+
type = types.str;
+
default = "";
+
description = ''
+
SMTP authentication password used when sending outgoing mail.
+
'';
+
};
+
+
security = mkOption {
+
type = types.enum ["" "ssl" "tls"];
+
default = "";
+
description = ''
+
Used to select a secure SMTP connection. Allowed values: ssl, tls,
+
or empty.
+
'';
+
};
+
+
fromName = mkOption {
+
type = types.str;
+
default = "Tiny Tiny RSS";
+
description = ''
+
Name for sending outgoing mail. This applies to password reset
+
notifications, digest emails and any other mail.
+
'';
+
};
+
+
fromAddress = mkOption {
+
type = types.str;
+
default = "";
+
description = ''
+
Address for sending outgoing mail. This applies to password reset
+
notifications, digest emails and any other mail.
+
'';
+
};
+
+
digestSubject = mkOption {
+
type = types.str;
+
default = "[tt-rss] New headlines for last 24 hours";
+
description = ''
+
Subject line for email digests.
+
'';
+
};
+
};
+
+
sessionCookieLifetime = mkOption {
+
type = types.int;
+
default = 86400;
+
description = ''
+
Default lifetime of a session (e.g. login) cookie. In seconds,
+
0 means cookie will be deleted when browser closes.
+
'';
+
};
+
+
selfUrlPath = mkOption {
+
type = types.str;
+
description = ''
+
Full URL of your tt-rss installation. This should be set to the
+
location of tt-rss directory, e.g. http://example.org/tt-rss/
+
You need to set this option correctly otherwise several features
+
including PUSH, bookmarklets and browser integration will not work properly.
+
'';
+
example = "http://localhost";
+
};
+
+
feedCryptKey = mkOption {
+
type = types.str;
+
default = "";
+
description = ''
+
Key used for encryption of passwords for password-protected feeds
+
in the database. A string of 24 random characters. If left blank, encryption
+
is not used. Requires mcrypt functions.
+
Warning: changing this key will make your stored feed passwords impossible
+
to decrypt.
+
'';
+
};
+
+
singleUserMode = mkOption {
+
type = types.bool;
+
default = true;
+
+
description = ''
+
Operate in single user mode, disables all functionality related to
+
multiple users and authentication. Enabling this assumes you have
+
your tt-rss directory protected by other means (e.g. http auth).
+
'';
+
};
+
+
simpleUpdateMode = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
Enables fallback update mode where tt-rss tries to update feeds in
+
background while tt-rss is open in your browser.
+
If you don't have a lot of feeds and don't want to or can't run
+
background processes while not running tt-rss, this method is generally
+
viable to keep your feeds up to date.
+
Still, there are more robust (and recommended) updating methods
+
available, you can read about them here: http://tt-rss.org/wiki/UpdatingFeeds
+
'';
+
};
+
+
forceArticlePurge = mkOption {
+
type = types.int;
+
default = 0;
+
description = ''
+
When this option is not 0, users ability to control feed purging
+
intervals is disabled and all articles (which are not starred)
+
older than this amount of days are purged.
+
'';
+
};
+
+
checkForUpdates = mkOption {
+
type = types.bool;
+
default = true;
+
description = ''
+
Check for updates automatically if running Git version
+
'';
+
};
+
+
enableGZipOutput = mkOption {
+
type = types.bool;
+
default = true;
+
description = ''
+
Selectively gzip output to improve wire performance. This requires
+
PHP Zlib extension on the server.
+
Enabling this can break tt-rss in several httpd/php configurations,
+
if you experience weird errors and tt-rss failing to start, blank pages
+
after login, or content encoding errors, disable it.
+
'';
+
};
+
+
plugins = mkOption {
+
type = types.listOf types.str;
+
default = ["auth_internal" "note"];
+
description = ''
+
List of plugins to load automatically for all users.
+
System plugins have to be specified here. Please enable at least one
+
authentication plugin here (auth_*).
+
Users may enable other user plugins from Preferences/Plugins but may not
+
disable plugins specified in this list.
+
Disabling auth_internal in this list would automatically disable
+
reset password link on the login form.
+
'';
+
};
+
+
logDestination = mkOption {
+
type = types.enum ["" "sql" "syslog"];
+
default = "sql";
+
description = ''
+
Log destination to use. Possible values: sql (uses internal logging
+
you can read in Preferences -> System), syslog - logs to system log.
+
Setting this to blank uses PHP logging (usually to http server
+
error.log).
+
'';
+
};
+
};
+
};
+
+
+
###### implementation
+
+
config = let
+
root = "/var/lib/tt-rss";
+
in mkIf cfg.enable {
+
+
services.phpfpm.pools = if cfg.pool == "${poolName}" then {
+
"${poolName}" = {
+
listen = "/var/run/phpfpm/${poolName}.sock";
+
extraConfig = ''
+
listen.owner = nginx
+
listen.group = nginx
+
listen.mode = 0600
+
user = nginx
+
pm = dynamic
+
pm.max_children = 75
+
pm.start_servers = 10
+
pm.min_spare_servers = 5
+
pm.max_spare_servers = 20
+
pm.max_requests = 500
+
catch_workers_output = 1
+
'';
+
};
+
} else {};
+
+
+
services.nginx.virtualHosts = if cfg.virtualHost == "${virtualHostName}" then {
+
"${virtualHostName}" = {
+
root = "${root}";
+
extraConfig = ''
+
access_log /var/log/nginx-${virtualHostName}-access.log;
+
error_log /var/log/nginx-${virtualHostName}-error.log;
+
'';
+
+
locations."/" = {
+
extraConfig = ''
+
index index.php;
+
'';
+
};
+
+
locations."~ \.php$" = {
+
extraConfig = ''
+
fastcgi_split_path_info ^(.+\.php)(/.+)$;
+
fastcgi_pass unix:${config.services.phpfpm.pools."${cfg.pool}".listen};
+
fastcgi_index index.php;
+
fastcgi_param SCRIPT_FILENAME ${root}/$fastcgi_script_name;
+
+
include ${pkgs.nginx}/conf/fastcgi_params;
+
'';
+
};
+
};
+
} else {};
+
+
+
systemd.services.tt-rss = let
+
dbService = if cfg.database.type == "pgsql" then "postgresql.service" else "mysql.service";
+
in {
+
+
description = "Tiny Tiny RSS feeds update daemon";
+
+
preStart = let
+
callSql = if cfg.database.type == "pgsql" then (e: ''
+
${optionalString (cfg.database.password != null)
+
"PGPASSWORD=${cfg.database.password}"} ${pkgs.postgresql95}/bin/psql \
+
-U ${cfg.database.user} \
+
-h ${cfg.database.host} \
+
--port ${toString dbPort} \
+
-c '${e}' \
+
${cfg.database.name}'')
+
+
else if cfg.database.type == "mysql" then (e: ''
+
echo '${e}' | ${pkgs.mysql}/bin/mysql \
+
${optionalString (cfg.database.password != null)
+
"-p${cfg.database.password}"} \
+
-u ${cfg.database.user} \
+
-h ${cfg.database.host} \
+
-P ${toString dbPort} \
+
${cfg.database.name}'')
+
+
else "";
+
+
in ''
+
rm -rf "${root}/*"
+
mkdir -m 755 -p "${root}"
+
cp -r "${pkgs.tt-rss}/"* "${root}"
+
ln -sf "${tt-rss-config}" "${root}/config.php"
+
chown -R "${cfg.user}" "${root}"
+
chmod -R 755 "${root}"
+
'' + (optionalString (cfg.database.type == "pgsql") ''
+
+
exists=$(${callSql "select count(*) > 0 from pg_tables where tableowner = user"} \
+
| tail -n+3 | head -n-2 | sed -e 's/[ \n\t]*//')
+
+
if [ "$exists" == 'f' ]; then
+
${callSql "\\i ${pkgs.tt-rss}/schema/ttrss_schema_${cfg.database.type}.sql"}
+
else
+
echo 'The database contains some data. Leaving it as it is.'
+
fi;
+
'') + (optionalString (cfg.database.type == "mysql") ''
+
+
exists=$(${callSql "select count(*) > 0 from information_schema.tables where table_schema = schema()"} \
+
| tail -n+2 | sed -e 's/[ \n\t]*//')
+
+
if [ "$exists" == '0' ]; then
+
${callSql "\\. ${pkgs.tt-rss}/schema/ttrss_schema_${cfg.database.type}.sql"}
+
else
+
echo 'The database contains some data. Leaving it as it is.'
+
fi;
+
'');
+
+
serviceConfig = {
+
User = "${cfg.user}";
+
ExecStart = "${pkgs.php}/bin/php /var/lib/tt-rss/update.php --daemon";
+
StandardOutput = "syslog";
+
StandardError = "syslog";
+
PermissionsStartOnly = true;
+
};
+
+
wantedBy = [ "multi-user.target" ];
+
requires = ["${dbService}"];
+
after = ["network.target" "${dbService}"];
+
};
+
};
+
}
+
+13 -21
nixos/modules/services/web-servers/phpfpm.nix nixos/modules/services/web-servers/phpfpm/default.nix
···
pidFile = "${stateDir}/phpfpm.pid";
+
mkPool = n: p: ''
+
[${n}]
+
listen = ${p.listen}
+
${p.extraConfig}
+
'';
+
cfgFile = pkgs.writeText "phpfpm.conf" ''
[global]
pid = ${pidFile}
···
daemonize = yes
${cfg.extraConfig}
-
${concatStringsSep "\n" (mapAttrsToList (n: v: "[${n}]\n${v}") cfg.poolConfigs)}
+
${concatStringsSep "\n" (mapAttrsToList mkPool cfg.pools)}
'';
phpIni = pkgs.writeText "php.ini" ''
···
"Options appended to the PHP configuration file <filename>php.ini</filename>.";
};
-
poolConfigs = mkOption {
-
type = types.attrsOf types.lines;
+
pools = mkOption {
+
type = types.attrsOf (types.submodule (import ./pool-options.nix {
+
inherit lib;
+
}));
default = {};
-
example = literalExample ''
-
{ mypool = '''
-
listen = /run/phpfpm/mypool
-
user = nobody
-
pm = dynamic
-
pm.max_children = 75
-
pm.start_servers = 10
-
pm.min_spare_servers = 5
-
pm.max_spare_servers = 20
-
pm.max_requests = 500
-
''';
-
}
-
'';
description = ''
-
A mapping between PHP FPM pool names and their configurations.
-
See the documentation on <literal>php-fpm.conf</literal> for
-
details on configuration directives. If no pools are defined,
-
the phpfpm service is disabled.
+
If no pools are defined, the phpfpm service is disabled.
'';
};
};
};
-
config = mkIf (cfg.poolConfigs != {}) {
+
config = mkIf (cfg.pools != {}) {
systemd.services.phpfpm = {
wantedBy = [ "multi-user.target" ];
+35
nixos/modules/services/web-servers/phpfpm/pool-options.nix
···
+
{ lib }:
+
+
with lib; {
+
+
options = {
+
+
listen = mkOption {
+
type = types.str;
+
example = "/path/to/unix/socket";
+
description = ''
+
The address on which to accept FastCGI requests.
+
'';
+
};
+
+
extraConfig = mkOption {
+
type = types.lines;
+
example = ''
+
user = nobody
+
pm = dynamic
+
pm.max_children = 75
+
pm.start_servers = 10
+
pm.min_spare_servers = 5
+
pm.max_spare_servers = 20
+
pm.max_requests = 500
+
'';
+
+
description = ''
+
Extra lines that go into the pool configuration.
+
See the documentation on <literal>php-fpm.conf</literal> for
+
details on configuration directives.
+
'';
+
};
+
};
+
}
+
+28
pkgs/servers/tt-rss/default.nix
···
+
{ stdenv, fetchgit }:
+
+
stdenv.mkDerivation rec {
+
name = "tt-rss-${version}";
+
version = "16.3";
+
+
src = fetchgit {
+
url = "https://tt-rss.org/gitlab/fox/tt-rss.git";
+
rev = "refs/tags/${version}";
+
sha256 = "1584lcq6kcy9f8ik5djb9apck9hxvfpl54sn6yhl3pdfrfdj3nw5";
+
};
+
+
buildPhases = ["unpackPhase" "installPhase"];
+
+
installPhase = ''
+
mkdir $out
+
cp -ra * $out/
+
'';
+
+
meta = with stdenv.lib; {
+
description = "Web-based news feed (RSS/Atom) aggregator";
+
license = licenses.gpl2Plus;
+
homepage = http://tt-rss.org;
+
maintainers = with maintainers; [ zohl ];
+
platforms = platforms.all;
+
};
+
}
+
+2
pkgs/top-level/all-packages.nix
···
torque = callPackage ../servers/computing/torque { };
+
tt-rss = callPackage ../servers/tt-rss { };
+
axis2 = callPackage ../servers/http/tomcat/axis2 { };
unifi = callPackage ../servers/unifi { };