312 lines
9.8 KiB
Nix
312 lines
9.8 KiB
Nix
{ config, lib, pkgs, ... }:
|
||
|
||
let
|
||
cfg = config.services.pretix;
|
||
name = "pretix";
|
||
user = "pretix";
|
||
group = "pretix";
|
||
bind = {
|
||
host = "127.0.0.1";
|
||
port = 8000;
|
||
};
|
||
postgresql = {
|
||
database = "pretix";
|
||
user = "pretix";
|
||
password = "pretix";
|
||
};
|
||
redisPort = 6379;
|
||
urlScheme = if cfg.enableTls then "https" else "http";
|
||
url = "${urlScheme}://${cfg.domain}";
|
||
toBool = x: if x then "on" else "off";
|
||
hstsHeader = if cfg.enableTls then "add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\" always;" else "";
|
||
pythonPackages = pkgs.pretix.passthru.pythonModule.passthru.pkgs;
|
||
python = pkgs.pretix.passthru.python;
|
||
runCommandArgs = {
|
||
# Sets PYTHONPATH in derivation
|
||
buildInputs = [
|
||
pkgs.pretix
|
||
pythonPackages.gunicorn
|
||
pythonPackages.celery
|
||
];
|
||
};
|
||
staticRoot = pkgs.pretix-static;
|
||
environmentFile = pkgs.runCommand "pretix-environ" runCommandArgs (''
|
||
cat > $out <<EOF
|
||
DATA_DIR = /var/pretix
|
||
DJANGO_SETTINGS_MODULE=pretix_wrapper.settings
|
||
PRETIX_CELERY_BACKEND=redis://127.0.0.1:${toString redisPort}/2
|
||
PRETIX_CELERY_BROKER=redis://127.0.0.1:${toString redisPort}/1
|
||
PRETIX_DATABASE_BACKEND=postgresql
|
||
PRETIX_DATABASE_HOST=localhost
|
||
PRETIX_DATABASE_NAME=${postgresql.database}
|
||
PRETIX_DATABASE_PASSWORD=${postgresql.password}
|
||
PRETIX_DATABASE_USER=${postgresql.user}
|
||
PRETIX_LOCALE_DEFAULT=${cfg.locale}
|
||
PRETIX_LOCALE_TIMEZONE=${cfg.timezone}
|
||
PRETIX_PRETIX_INSTANCE_NAME=${cfg.instanceName}
|
||
PRETIX_PRETIX_PASSWORD_RESET=${toBool cfg.passwordReset}
|
||
PRETIX_PRETIX_REGISTRATION=${toBool cfg.enableRegistration}
|
||
PRETIX_PRETIX_URL=${url}
|
||
PRETIX_REDIS_LOCATION=redis://127.0.0.1:${toString redisPort}/0
|
||
PRETIX_REDIS_SESSIONS=true
|
||
PRETIX_STATIC_ROOT=${staticRoot}
|
||
'' + (
|
||
if cfg.mail.enable then
|
||
''
|
||
PRETIX_MAIL_FROM=${toString cfg.mail.from}
|
||
PRETIX_MAIL_HOST="${cfg.mail.host}"
|
||
PRETIX_MAIL_PORT=${toString cfg.mail.port}
|
||
'' else ""
|
||
) +
|
||
''
|
||
PYTHONPATH=$PYTHONPATH
|
||
EOF
|
||
'');
|
||
mkTimer = { description, unit, onCalendar }: {
|
||
inherit description;
|
||
requires = [ "pretix-migrate.service" ];
|
||
after = [ "network.target" ];
|
||
wantedBy = [ "timers.target" ];
|
||
timerConfig = {
|
||
Persistent = true;
|
||
OnCalendar = onCalendar;
|
||
Unit = unit;
|
||
};
|
||
};
|
||
in
|
||
{
|
||
options.services.pretix = with lib; with lib.types; {
|
||
enable = mkEnableOption "Enable pretix ticket shop application";
|
||
instanceName = mkOption {
|
||
type = types.str;
|
||
description = "The name of this installation.";
|
||
};
|
||
domain = mkOption {
|
||
type = types.str;
|
||
description = "The installation’s main domain";
|
||
example = "pretix.example.net";
|
||
};
|
||
extraDomains = mkOption {
|
||
type = listOf str;
|
||
description = "A list of extra domains";
|
||
default = [ ];
|
||
};
|
||
enableTls = mkEnableOption "Whether to use TLS or not";
|
||
enableRegistration = mkEnableOption "Enables or disables the registration of new admin users.";
|
||
passwordReset = mkEnableOption "Enables or disables password reset.";
|
||
locale = mkOption {
|
||
type = types.str;
|
||
description = "The system’s default locale.";
|
||
};
|
||
timezone = mkOption {
|
||
type = types.str;
|
||
description = "The system’s default timezone as a pytz name.";
|
||
};
|
||
secretsFile = mkOption {
|
||
type = types.path;
|
||
description = "Path to the sops secrets file which stores pretix.cfg settings.";
|
||
};
|
||
mail = {
|
||
enable = mkEnableOption "Enables or disables emailing.";
|
||
from = mkOption {
|
||
type = types.str;
|
||
description = "The email address to set as From header in outgoing emails by the system.";
|
||
};
|
||
host = mkOption {
|
||
type = types.str;
|
||
description = "The SMTP Host to connect to.";
|
||
default = "localhost";
|
||
};
|
||
port = mkOption {
|
||
type = types.port;
|
||
description = "The SMTP Port to connect to.";
|
||
default = 25;
|
||
};
|
||
admins = mkOption {
|
||
type = listOf str;
|
||
description = ''
|
||
Comma-separated list of email addresses that should receive a report about every error code 500 thrown by pretix.
|
||
'';
|
||
default = [ ];
|
||
};
|
||
};
|
||
banktool = {
|
||
enable = mkEnableOption "Enable tool to query bank account and sync transaction data to pretix server.";
|
||
days = mkOption {
|
||
type = types.int;
|
||
description = "The timeframe of transaction to fetch from the bank in days.";
|
||
};
|
||
};
|
||
};
|
||
|
||
config = lib.mkIf cfg.enable {
|
||
sops.secrets.pretix-cfg = {
|
||
sopsFile = cfg.secretsFile;
|
||
};
|
||
sops.secrets.pretix-banktool-cfg = {
|
||
sopsFile = cfg.secretsFile;
|
||
};
|
||
|
||
users.users."${user}" = {
|
||
createHome = true;
|
||
description = "Pretix user";
|
||
home = "/var/pretix";
|
||
isNormalUser = false;
|
||
isSystemUser = true;
|
||
group = group;
|
||
};
|
||
users.groups."${group}" = { };
|
||
|
||
services.nginx = {
|
||
enable = true;
|
||
recommendedGzipSettings = true;
|
||
recommendedOptimisation = true;
|
||
recommendedProxySettings = true;
|
||
recommendedTlsSettings = true;
|
||
virtualHosts = lib.listToAttrs (map
|
||
(d: {
|
||
name = d;
|
||
value = {
|
||
enableACME = cfg.enableTls;
|
||
forceSSL = cfg.enableTls;
|
||
kTLS = cfg.enableTls;
|
||
locations."/" = {
|
||
proxyPass = "http://${bind.host}:${toString bind.port}";
|
||
};
|
||
extraConfig = ''
|
||
${hstsHeader}
|
||
'';
|
||
};
|
||
})
|
||
([ cfg.domain ] ++ cfg.extraDomains)
|
||
);
|
||
};
|
||
|
||
services.postgresql = {
|
||
enable = true;
|
||
enableTCPIP = true;
|
||
authentication = pkgs.lib.mkOverride 10 ''
|
||
local all all trust
|
||
host all all ::1/128 trust
|
||
'';
|
||
initialScript = pkgs.writeText "backend-initScript" ''
|
||
CREATE ROLE ${postgresql.user} WITH LOGIN PASSWORD '${postgresql.password}' CREATEDB;
|
||
CREATE DATABASE ${postgresql.database};
|
||
GRANT ALL PRIVILEGES ON DATABASE ${postgresql.database} TO ${postgresql.user};
|
||
'';
|
||
};
|
||
|
||
services.redis.servers.pretix = {
|
||
enable = true;
|
||
port = redisPort;
|
||
databases = 3;
|
||
};
|
||
|
||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||
|
||
systemd.services.pretix-migrate = {
|
||
description = "Pretix DB Migrations";
|
||
serviceConfig = {
|
||
Type = "oneshot";
|
||
EnvironmentFile = environmentFile;
|
||
User = user;
|
||
LoadCredential = "config:${config.sops.secrets.pretix-cfg.path}";
|
||
};
|
||
script = ''
|
||
export PRETIX_CONFIG_FILE="$CREDENTIALS_DIRECTORY/config"
|
||
${pkgs.pretix}/bin/pretix migrate
|
||
'';
|
||
};
|
||
|
||
systemd.services.pretix-web = {
|
||
description = "Pretix Web Service";
|
||
serviceConfig = {
|
||
Type = "simple";
|
||
Restart = "on-failure";
|
||
EnvironmentFile = environmentFile;
|
||
User = user;
|
||
LoadCredential = "config:${config.sops.secrets.pretix-cfg.path}";
|
||
ExecStart = pkgs.writeScript "webserver" ''
|
||
#!${pkgs.runtimeShell}
|
||
set -euo pipefail
|
||
export PRETIX_CONFIG_FILE="$CREDENTIALS_DIRECTORY/config"
|
||
exec ${pythonPackages.gunicorn}/bin/gunicorn pretix.wsgi --name ${name} \
|
||
--workers 3 \
|
||
--log-level=info \
|
||
--bind=${bind.host}:${toString bind.port}
|
||
'';
|
||
};
|
||
wantedBy = [ "multi-user.target" ];
|
||
requires = [ "pretix-migrate.service" ];
|
||
after = [ "network.target" ];
|
||
};
|
||
|
||
systemd.services.pretix-worker = {
|
||
description = "Pretix Celery (Worker) Service";
|
||
serviceConfig = {
|
||
Type = "simple";
|
||
Restart = "on-failure";
|
||
EnvironmentFile = environmentFile;
|
||
User = user;
|
||
LoadCredential = "config:${config.sops.secrets.pretix-cfg.path}";
|
||
ExecStart = pkgs.writeScript "worker" ''
|
||
#!${pkgs.runtimeShell}
|
||
set -euo pipefail
|
||
export PRETIX_CONFIG_FILE="$CREDENTIALS_DIRECTORY/config"
|
||
exec ${pythonPackages.celery}/bin/celery -A pretix.celery_app worker -l info
|
||
'';
|
||
};
|
||
wantedBy = [ "multi-user.target" ];
|
||
requires = [ "pretix-migrate.service" ];
|
||
after = [ "network.target" ];
|
||
};
|
||
|
||
systemd.services.pretix-runperiodic = {
|
||
description = "Pretix periodic tasks";
|
||
serviceConfig = {
|
||
Type = "oneshot";
|
||
EnvironmentFile = environmentFile;
|
||
User = user;
|
||
LoadCredential = "config:${config.sops.secrets.pretix-cfg.path}";
|
||
};
|
||
script = ''
|
||
export PRETIX_CONFIG_FILE="$CREDENTIALS_DIRECTORY/config"
|
||
${pkgs.pretix}/bin/pretix runperiodic
|
||
'';
|
||
};
|
||
|
||
# Once every 5 minutes
|
||
systemd.timers.pretix-runperiodic = mkTimer {
|
||
description = "Run pretix tasks";
|
||
unit = "pretix-runperiodic.service";
|
||
onCalendar = "*:0/5";
|
||
};
|
||
|
||
systemd.services.pretix-banktool = lib.mkIf cfg.banktool.enable {
|
||
description = "Tool to query bank account and sync transaction data to pretix server.";
|
||
serviceConfig = {
|
||
Type = "oneshot";
|
||
DynamicUser = true;
|
||
CapabilityBoundingSet = null;
|
||
PrivateUsers = true;
|
||
ProtectHome = true;
|
||
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
|
||
RestrictNamespaces = true;
|
||
SystemCallFilter = "@system-service";
|
||
LoadCredential = "config:${config.sops.secrets.pretix-banktool-cfg.path}";
|
||
};
|
||
script = "${pkgs.pretix-banktool}/bin/pretix-banktool upload \"$CREDENTIALS_DIRECTORY/config\" --days=${toString cfg.banktool.days}";
|
||
};
|
||
|
||
systemd.timers.pretix-banktool = lib.mkIf cfg.banktool.enable {
|
||
description = "Run tool to query bank account and sync transaction data to pretix server.";
|
||
after = [ "network.target" ];
|
||
wantedBy = [ "timers.target" ];
|
||
timerConfig = {
|
||
Persistent = true;
|
||
OnCalendar = "*-*-* *:00:00";
|
||
Unit = "pretix-banktool.service";
|
||
};
|
||
};
|
||
};
|
||
}
|