1 { lib, config, pkgs, ... }:
4 cfg = config.services.onlyoffice;
7 options.services.onlyoffice = {
8 enable = lib.mkEnableOption "OnlyOffice DocumentServer";
10 enableExampleServer = lib.mkEnableOption "OnlyOffice example server";
12 hostname = lib.mkOption {
14 default = "localhost";
15 description = "FQDN for the OnlyOffice instance.";
18 jwtSecretFile = lib.mkOption {
19 type = lib.types.nullOr lib.types.str;
22 Path to a file that contains the secret to sign web requests using JSON Web Tokens.
23 If left at the default value null signing is disabled.
27 package = lib.mkPackageOption pkgs "onlyoffice-documentserver" { };
30 type = lib.types.port;
32 description = "Port the OnlyOffice document server should listen on.";
35 examplePort = lib.mkOption {
36 type = lib.types.port;
38 description = "Port the OnlyOffice example server should listen on.";
41 postgresHost = lib.mkOption {
43 default = "/run/postgresql";
44 description = "The Postgresql hostname or socket path OnlyOffice should connect to.";
47 postgresName = lib.mkOption {
49 default = "onlyoffice";
50 description = "The name of database OnlyOffice should use.";
53 postgresPasswordFile = lib.mkOption {
54 type = lib.types.nullOr lib.types.str;
57 Path to a file that contains the password OnlyOffice should use to connect to Postgresql.
58 Unused when using socket authentication.
62 postgresUser = lib.mkOption {
64 default = "onlyoffice";
66 The username OnlyOffice should use to connect to Postgresql.
67 Unused when using socket authentication.
71 rabbitmqUrl = lib.mkOption {
73 default = "amqp://guest:guest@localhost:5672";
74 description = "The Rabbitmq in amqp URI style OnlyOffice should connect to.";
78 config = lib.mkIf cfg.enable {
81 enable = lib.mkDefault true;
82 # misses text/csv, font/ttf, application/x-font-ttf, application/rtf, application/wasm
83 recommendedGzipSettings = lib.mkDefault true;
84 recommendedProxySettings = lib.mkDefault true;
87 # /etc/nginx/includes/http-common.conf
88 onlyoffice-docservice = {
89 servers = { "localhost:${toString cfg.port}" = { }; };
91 onlyoffice-example = lib.mkIf cfg.enableExampleServer {
92 servers = { "localhost:${toString cfg.examplePort}" = { }; };
96 virtualHosts.${cfg.hostname} = {
98 # /etc/nginx/includes/ds-docservice.conf
99 "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(web-apps\/apps\/api\/documents\/api\.js)$".extraConfig = ''
101 alias ${cfg.package}/var/www/onlyoffice/documentserver/$2;
103 "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(web-apps)(\/.*\.json)$".extraConfig = ''
105 error_log /dev/null crit;
106 alias ${cfg.package}/var/www/onlyoffice/documentserver/$2$3;
108 "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(sdkjs-plugins)(\/.*\.json)$".extraConfig = ''
110 error_log /dev/null crit;
111 alias ${cfg.package}/var/www/onlyoffice/documentserver/$2$3;
113 "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(web-apps|sdkjs|sdkjs-plugins|fonts)(\/.*)$".extraConfig = ''
115 alias ${cfg.package}/var/www/onlyoffice/documentserver/$2$3;
117 "~* ^(\/cache\/files.*)(\/.*)".extraConfig = ''
118 alias /var/lib/onlyoffice/documentserver/App_Data$1;
119 add_header Content-Disposition "attachment; filename*=UTF-8''$arg_filename";
121 set $secret_string verysecretstring;
122 secure_link $arg_md5,$arg_expires;
123 secure_link_md5 "$secure_link_expires$uri$secret_string";
125 if ($secure_link = "") {
129 if ($secure_link = "0") {
133 "~* ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(internal)(\/.*)$".extraConfig = ''
136 proxy_pass http://onlyoffice-docservice/$2$3;
138 "~* ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(info)(\/.*)$".extraConfig = ''
141 proxy_pass http://onlyoffice-docservice/$2$3;
144 proxy_pass http://onlyoffice-docservice;
146 "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?(\/doc\/.*)".extraConfig = ''
147 proxy_pass http://onlyoffice-docservice$2;
148 proxy_http_version 1.1;
150 "/${cfg.package.version}/".extraConfig = ''
151 proxy_pass http://onlyoffice-docservice/;
153 "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(dictionaries)(\/.*)$".extraConfig = ''
155 alias ${cfg.package}/var/www/onlyoffice/documentserver/$2$3;
157 # /etc/nginx/includes/ds-example.conf
158 "~ ^(\/welcome\/.*)$".extraConfig = ''
160 alias ${cfg.package}/var/www/onlyoffice/documentserver-example$1;
163 "/example/".extraConfig = lib.mkIf cfg.enableExampleServer ''
164 proxy_pass http://onlyoffice-example/;
165 proxy_set_header X-Forwarded-Path /example;
169 rewrite ^/$ /welcome/ redirect;
170 rewrite ^\/OfficeWeb(\/apps\/.*)$ /${cfg.package.version}/web-apps$1 redirect;
171 rewrite ^(\/web-apps\/apps\/(?!api\/).*)$ /${cfg.package.version}$1 redirect;
173 # based on https://github.com/ONLYOFFICE/document-server-package/blob/master/common/documentserver/nginx/includes/http-common.conf.m4#L29-L34
174 # without variable indirection and correct variable names
175 proxy_set_header Host $host;
176 proxy_set_header X-Forwarded-Host $host;
177 proxy_set_header X-Forwarded-Proto $scheme;
178 # required for CSP to take effect
179 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
180 # required for websocket
181 proxy_set_header Upgrade $http_upgrade;
182 proxy_set_header Connection $connection_upgrade;
187 rabbitmq.enable = lib.mkDefault true;
190 enable = lib.mkDefault true;
191 ensureDatabases = [ "onlyoffice" ];
194 ensureDBOwnership = true;
200 onlyoffice-converter = {
201 description = "onlyoffice converter";
202 after = [ "network.target" "onlyoffice-docservice.service" "postgresql.service" ];
203 requires = [ "network.target" "onlyoffice-docservice.service" "postgresql.service" ];
204 wantedBy = [ "multi-user.target" ];
206 ExecStart = "${cfg.package.fhs}/bin/onlyoffice-wrapper FileConverter/converter /run/onlyoffice/config";
207 Group = "onlyoffice";
209 RuntimeDirectory = "onlyoffice";
210 StateDirectory = "onlyoffice";
216 onlyoffice-docservice =
218 onlyoffice-prestart = pkgs.writeShellScript "onlyoffice-prestart" ''
219 PATH=$PATH:${lib.makeBinPath (with pkgs; [ jq moreutils config.services.postgresql.package ])}
221 mkdir -p /run/onlyoffice/config/ /var/lib/onlyoffice/documentserver/sdkjs/{slide/themes,common}/ /var/lib/onlyoffice/documentserver/{fonts,server/FileConverter/bin}/
222 cp -r ${cfg.package}/etc/onlyoffice/documentserver/* /run/onlyoffice/config/
223 chmod u+w /run/onlyoffice/config/default.json
225 # Allow members of the onlyoffice group to serve files under /var/lib/onlyoffice/documentserver/App_Data
226 chmod g+x /var/lib/onlyoffice/documentserver
228 cp /run/onlyoffice/config/default.json{,.orig}
230 # for a mapping of environment variables from the docker container to json options see
231 # https://github.com/ONLYOFFICE/Docker-DocumentServer/blob/master/run-document-server.sh
233 .services.CoAuthoring.server.port = ${toString cfg.port} |
234 .services.CoAuthoring.sql.dbHost = "${cfg.postgresHost}" |
235 .services.CoAuthoring.sql.dbName = "${cfg.postgresName}" |
236 ${lib.optionalString (cfg.postgresPasswordFile != null) ''
237 .services.CoAuthoring.sql.dbPass = "'"$(cat ${cfg.postgresPasswordFile})"'" |
239 .services.CoAuthoring.sql.dbUser = "${cfg.postgresUser}" |
240 ${lib.optionalString (cfg.jwtSecretFile != null) ''
241 .services.CoAuthoring.token.enable.browser = true |
242 .services.CoAuthoring.token.enable.request.inbox = true |
243 .services.CoAuthoring.token.enable.request.outbox = true |
244 .services.CoAuthoring.secret.inbox.string = "'"$(cat ${cfg.jwtSecretFile})"'" |
245 .services.CoAuthoring.secret.outbox.string = "'"$(cat ${cfg.jwtSecretFile})"'" |
246 .services.CoAuthoring.secret.session.string = "'"$(cat ${cfg.jwtSecretFile})"'" |
248 .rabbitmq.url = "${cfg.rabbitmqUrl}"
249 ' /run/onlyoffice/config/default.json | sponge /run/onlyoffice/config/default.json
251 if psql -d onlyoffice -c "SELECT 'task_result'::regclass;" >/dev/null; then
252 psql -f ${cfg.package}/var/www/onlyoffice/documentserver/server/schema/postgresql/removetbl.sql
253 psql -f ${cfg.package}/var/www/onlyoffice/documentserver/server/schema/postgresql/createdb.sql
255 psql -f ${cfg.package}/var/www/onlyoffice/documentserver/server/schema/postgresql/createdb.sql
260 description = "onlyoffice documentserver";
261 after = [ "network.target" "postgresql.service" ];
262 requires = [ "postgresql.service" ];
263 wantedBy = [ "multi-user.target" ];
265 ExecStart = "${cfg.package.fhs}/bin/onlyoffice-wrapper DocService/docservice /run/onlyoffice/config";
266 ExecStartPre = [ onlyoffice-prestart ];
267 Group = "onlyoffice";
269 RuntimeDirectory = "onlyoffice";
270 StateDirectory = "onlyoffice";
279 description = "OnlyOffice Service";
280 group = "onlyoffice";
284 nginx.extraGroups = [ "onlyoffice" ];
287 users.groups.onlyoffice = { };