1{ config, lib, pkgs, ... }:
2
3with lib;
4let
5 gunicorn = pkgs.pythonPackages.gunicorn;
6 bepasty = pkgs.bepasty;
7 gevent = pkgs.pythonPackages.gevent;
8 python = pkgs.pythonPackages.python;
9 cfg = config.services.bepasty;
10 user = "bepasty";
11 group = "bepasty";
12 default_home = "/var/lib/bepasty";
13in
14{
15 options.services.bepasty = {
16 enable = mkEnableOption "Bepasty servers";
17
18 servers = mkOption {
19 default = {};
20 description = ''
21 configure a number of bepasty servers which will be started with
22 gunicorn.
23 '';
24 type = with types ; attrsOf (submodule ({ config, ... } : {
25
26 options = {
27
28 bind = mkOption {
29 type = types.str;
30 description = ''
31 Bind address to be used for this server.
32 '';
33 example = "0.0.0.0:8000";
34 default = "127.0.0.1:8000";
35 };
36
37 dataDir = mkOption {
38 type = types.str;
39 description = ''
40 Path to the directory where the pastes will be saved to
41 '';
42 default = default_home+"/data";
43 };
44
45 defaultPermissions = mkOption {
46 type = types.str;
47 description = ''
48 default permissions for all unauthenticated accesses.
49 '';
50 example = "read,create,delete";
51 default = "read";
52 };
53
54 extraConfig = mkOption {
55 type = types.lines;
56 description = ''
57 Extra configuration for bepasty server to be appended on the
58 configuration.
59 see https://bepasty-server.readthedocs.org/en/latest/quickstart.html#configuring-bepasty
60 for all options.
61 '';
62 default = "";
63 example = ''
64 PERMISSIONS = {
65 'myadminsecret': 'admin,list,create,read,delete',
66 }
67 MAX_ALLOWED_FILE_SIZE = 5 * 1000 * 1000
68 '';
69 };
70
71 secretKey = mkOption {
72 type = types.str;
73 description = ''
74 server secret for safe session cookies, must be set.
75
76 Warning: this secret is stored in the WORLD-READABLE Nix store!
77
78 It's recommended to use <option>secretKeyFile</option>
79 which takes precedence over <option>secretKey</option>.
80 '';
81 default = "";
82 };
83
84 secretKeyFile = mkOption {
85 type = types.nullOr types.str;
86 default = null;
87 description = ''
88 A file that contains the server secret for safe session cookies, must be set.
89
90 <option>secretKeyFile</option> takes precedence over <option>secretKey</option>.
91
92 Warning: when <option>secretKey</option> is non-empty <option>secretKeyFile</option>
93 defaults to a file in the WORLD-READABLE Nix store containing that secret.
94 '';
95 };
96
97 workDir = mkOption {
98 type = types.str;
99 description = ''
100 Path to the working directory (used for config and pidfile).
101 Defaults to the users home directory.
102 '';
103 default = default_home;
104 };
105
106 };
107 config = {
108 secretKeyFile = mkDefault (
109 if config.secretKey != ""
110 then toString (pkgs.writeTextFile {
111 name = "bepasty-secret-key";
112 text = config.secretKey;
113 })
114 else null
115 );
116 };
117 }));
118 };
119 };
120
121 config = mkIf cfg.enable {
122
123 environment.systemPackages = [ bepasty ];
124
125 # creates gunicorn systemd service for each configured server
126 systemd.services = mapAttrs' (name: server:
127 nameValuePair ("bepasty-server-${name}-gunicorn")
128 ({
129 description = "Bepasty Server ${name}";
130 wantedBy = [ "multi-user.target" ];
131 after = [ "network.target" ];
132 restartIfChanged = true;
133
134 environment = let
135 penv = python.buildEnv.override {
136 extraLibs = [ bepasty gevent ];
137 };
138 in {
139 BEPASTY_CONFIG = "${server.workDir}/bepasty-${name}.conf";
140 PYTHONPATH= "${penv}/${python.sitePackages}/";
141 };
142
143 serviceConfig = {
144 Type = "simple";
145 PrivateTmp = true;
146 ExecStartPre = assert !isNull server.secretKeyFile; pkgs.writeScript "bepasty-server.${name}-init" ''
147 #!/bin/sh
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
152 SITENAME="${name}"
153 STORAGE_FILESYSTEM_DIRECTORY="${server.dataDir}"
154 SECRET_KEY="$(cat "${server.secretKeyFile}")"
155 DEFAULT_PERMISSIONS="${server.defaultPermissions}"
156 ${server.extraConfig}
157 EOF
158 '';
159 ExecStart = ''${gunicorn}/bin/gunicorn bepasty.wsgi --name ${name} \
160 -u ${user} \
161 -g ${group} \
162 --workers 3 --log-level=info \
163 --bind=${server.bind} \
164 --pid ${server.workDir}/gunicorn-${name}.pid \
165 -k gevent
166 '';
167 };
168 })
169 ) cfg.servers;
170
171 users.extraUsers = [{
172 uid = config.ids.uids.bepasty;
173 name = user;
174 group = group;
175 home = default_home;
176 }];
177
178 users.extraGroups = [{
179 name = group;
180 gid = config.ids.gids.bepasty;
181 }];
182 };
183}