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