1 { config, lib, pkgs, ... }:
5 gunicorn = pkgs.python3Packages.gunicorn;
6 bepasty = pkgs.bepasty;
7 gevent = pkgs.python3Packages.gevent;
8 python = pkgs.python3Packages.python;
9 cfg = config.services.bepasty;
12 default_home = "/var/lib/bepasty";
15 options.services.bepasty = {
16 enable = mkEnableOption (lib.mdDoc "Bepasty servers");
20 description = lib.mdDoc ''
21 configure a number of bepasty servers which will be started with
24 type = with types ; attrsOf (submodule ({ config, ... } : {
30 description = lib.mdDoc ''
31 Bind address to be used for this server.
33 example = "0.0.0.0:8000";
34 default = "127.0.0.1:8000";
39 description = lib.mdDoc ''
40 Path to the directory where the pastes will be saved to
42 default = default_home+"/data";
45 defaultPermissions = mkOption {
47 description = lib.mdDoc ''
48 default permissions for all unauthenticated accesses.
50 example = "read,create,delete";
54 extraConfig = mkOption {
56 description = lib.mdDoc ''
57 Extra configuration for bepasty server to be appended on the
59 see https://bepasty-server.readthedocs.org/en/latest/quickstart.html#configuring-bepasty
65 'myadminsecret': 'admin,list,create,read,delete',
67 MAX_ALLOWED_FILE_SIZE = 5 * 1000 * 1000
71 secretKey = mkOption {
73 description = lib.mdDoc ''
74 server secret for safe session cookies, must be set.
76 Warning: this secret is stored in the WORLD-READABLE Nix store!
78 It's recommended to use {option}`secretKeyFile`
79 which takes precedence over {option}`secretKey`.
84 secretKeyFile = mkOption {
85 type = types.nullOr types.str;
87 description = lib.mdDoc ''
88 A file that contains the server secret for safe session cookies, must be set.
90 {option}`secretKeyFile` takes precedence over {option}`secretKey`.
92 Warning: when {option}`secretKey` is non-empty {option}`secretKeyFile`
93 defaults to a file in the WORLD-READABLE Nix store containing that secret.
99 description = lib.mdDoc ''
100 Path to the working directory (used for config and pidfile).
101 Defaults to the users home directory.
103 default = default_home;
108 secretKeyFile = mkDefault (
109 if config.secretKey != ""
110 then toString (pkgs.writeTextFile {
111 name = "bepasty-secret-key";
112 text = config.secretKey;
121 config = mkIf cfg.enable {
123 environment.systemPackages = [ bepasty ];
125 # creates gunicorn systemd service for each configured server
126 systemd.services = mapAttrs' (name: server:
127 nameValuePair ("bepasty-server-${name}-gunicorn")
129 description = "Bepasty Server ${name}";
130 wantedBy = [ "multi-user.target" ];
131 after = [ "network.target" ];
132 restartIfChanged = true;
135 penv = python.buildEnv.override {
136 extraLibs = [ bepasty gevent ];
139 BEPASTY_CONFIG = "${server.workDir}/bepasty-${name}.conf";
140 PYTHONPATH= "${penv}/${python.sitePackages}/";
146 ExecStartPre = assert server.secretKeyFile != null; pkgs.writeScript "bepasty-server.${name}-init" ''
148 mkdir -p "${server.workDir}"
149 mkdir -p "${server.dataDir}"
150 chown ${user}:${group} "${server.workDir}" "${server.dataDir}"
151 cat > ${server.workDir}/bepasty-${name}.conf <<EOF
153 STORAGE_FILESYSTEM_DIRECTORY="${server.dataDir}"
154 SECRET_KEY="$(cat "${server.secretKeyFile}")"
155 DEFAULT_PERMISSIONS="${server.defaultPermissions}"
156 ${server.extraConfig}
159 ExecStart = ''${gunicorn}/bin/gunicorn bepasty.wsgi --name ${name} \
162 --workers 3 --log-level=info \
163 --bind=${server.bind} \
164 --pid ${server.workDir}/gunicorn-${name}.pid \
171 users.users.${user} =
172 { uid = config.ids.uids.bepasty;
177 users.groups.${group}.gid = config.ids.gids.bepasty;