1{ config, lib, pkgs, ... }:
2
3let
4 cfg = config.services.calibre-web;
5
6 inherit (lib) concatStringsSep mkEnableOption mkIf mkOption optional optionalString types;
7in
8{
9 options = {
10 services.calibre-web = {
11 enable = mkEnableOption (lib.mdDoc "Calibre-Web");
12
13 listen = {
14 ip = mkOption {
15 type = types.str;
16 default = "::1";
17 description = lib.mdDoc ''
18 IP address that Calibre-Web should listen on.
19 '';
20 };
21
22 port = mkOption {
23 type = types.port;
24 default = 8083;
25 description = lib.mdDoc ''
26 Listen port for Calibre-Web.
27 '';
28 };
29 };
30
31 dataDir = mkOption {
32 type = types.str;
33 default = "calibre-web";
34 description = lib.mdDoc ''
35 The directory below {file}`/var/lib` where Calibre-Web stores its data.
36 '';
37 };
38
39 user = mkOption {
40 type = types.str;
41 default = "calibre-web";
42 description = lib.mdDoc "User account under which Calibre-Web runs.";
43 };
44
45 group = mkOption {
46 type = types.str;
47 default = "calibre-web";
48 description = lib.mdDoc "Group account under which Calibre-Web runs.";
49 };
50
51 openFirewall = mkOption {
52 type = types.bool;
53 default = false;
54 description = lib.mdDoc ''
55 Open ports in the firewall for the server.
56 '';
57 };
58
59 options = {
60 calibreLibrary = mkOption {
61 type = types.nullOr types.path;
62 default = null;
63 description = lib.mdDoc ''
64 Path to Calibre library.
65 '';
66 };
67
68 enableBookConversion = mkOption {
69 type = types.bool;
70 default = false;
71 description = lib.mdDoc ''
72 Configure path to the Calibre's ebook-convert in the DB.
73 '';
74 };
75
76 enableBookUploading = mkOption {
77 type = types.bool;
78 default = false;
79 description = lib.mdDoc ''
80 Allow books to be uploaded via Calibre-Web UI.
81 '';
82 };
83
84 reverseProxyAuth = {
85 enable = mkOption {
86 type = types.bool;
87 default = false;
88 description = lib.mdDoc ''
89 Enable authorization using auth proxy.
90 '';
91 };
92
93 header = mkOption {
94 type = types.str;
95 default = "";
96 description = lib.mdDoc ''
97 Auth proxy header name.
98 '';
99 };
100 };
101 };
102 };
103 };
104
105 config = mkIf cfg.enable {
106 systemd.services.calibre-web = let
107 appDb = "/var/lib/${cfg.dataDir}/app.db";
108 gdriveDb = "/var/lib/${cfg.dataDir}/gdrive.db";
109 calibreWebCmd = "${pkgs.calibre-web}/bin/calibre-web -p ${appDb} -g ${gdriveDb}";
110
111 settings = concatStringsSep ", " (
112 [
113 "config_port = ${toString cfg.listen.port}"
114 "config_uploading = ${if cfg.options.enableBookUploading then "1" else "0"}"
115 "config_allow_reverse_proxy_header_login = ${if cfg.options.reverseProxyAuth.enable then "1" else "0"}"
116 "config_reverse_proxy_login_header_name = '${cfg.options.reverseProxyAuth.header}'"
117 ]
118 ++ optional (cfg.options.calibreLibrary != null) "config_calibre_dir = '${cfg.options.calibreLibrary}'"
119 ++ optional cfg.options.enableBookConversion "config_converterpath = '${pkgs.calibre}/bin/ebook-convert'"
120 );
121 in
122 {
123 description = "Web app for browsing, reading and downloading eBooks stored in a Calibre database";
124 after = [ "network.target" ];
125 wantedBy = [ "multi-user.target" ];
126
127 serviceConfig = {
128 Type = "simple";
129 User = cfg.user;
130 Group = cfg.group;
131
132 StateDirectory = cfg.dataDir;
133 ExecStartPre = pkgs.writeShellScript "calibre-web-pre-start" (
134 ''
135 __RUN_MIGRATIONS_AND_EXIT=1 ${calibreWebCmd}
136
137 ${pkgs.sqlite}/bin/sqlite3 ${appDb} "update settings set ${settings}"
138 '' + optionalString (cfg.options.calibreLibrary != null) ''
139 test -f "${cfg.options.calibreLibrary}/metadata.db" || { echo "Invalid Calibre library"; exit 1; }
140 ''
141 );
142
143 ExecStart = "${calibreWebCmd} -i ${cfg.listen.ip}";
144 Restart = "on-failure";
145 };
146 };
147
148 networking.firewall = mkIf cfg.openFirewall {
149 allowedTCPPorts = [ cfg.listen.port ];
150 };
151
152 users.users = mkIf (cfg.user == "calibre-web") {
153 calibre-web = {
154 isSystemUser = true;
155 group = cfg.group;
156 };
157 };
158
159 users.groups = mkIf (cfg.group == "calibre-web") {
160 calibre-web = {};
161 };
162 };
163
164 meta.maintainers = with lib.maintainers; [ pborzenkov ];
165}