diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 82c0b5d74de3..3010a213705b 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1088,6 +1088,7 @@ ./services/web-apps/nifi.nix ./services/web-apps/node-red.nix ./services/web-apps/phylactery.nix + ./services/web-apps/onlyoffice.nix ./services/web-apps/pict-rs.nix ./services/web-apps/peertube.nix ./services/web-apps/plantuml-server.nix diff --git a/nixos/modules/services/web-apps/onlyoffice.nix b/nixos/modules/services/web-apps/onlyoffice.nix new file mode 100644 index 000000000000..ce6a3e835e3b --- /dev/null +++ b/nixos/modules/services/web-apps/onlyoffice.nix @@ -0,0 +1,288 @@ +{ lib, config, pkgs, ... }: + +with lib; + +let + cfg = config.services.onlyoffice; +in +{ + options.services.onlyoffice = { + enable = mkEnableOption "OnlyOffice DocumentServer"; + + enableExampleServer = mkEnableOption "OnlyOffice example server"; + + hostname = mkOption { + type = types.str; + default = "localhost"; + description = "FQDN for the onlyoffice instance."; + }; + + jwtSecretFile = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Path to a file that contains the secret to sign web requests using JSON Web Tokens. + If left at the default value null signing is disabled. + ''; + }; + + package = mkOption { + type = types.package; + default = pkgs.onlyoffice-documentserver; + defaultText = "pkgs.onlyoffice-documentserver"; + description = "Which package to use for the OnlyOffice instance."; + }; + + port = mkOption { + type = types.port; + default = 8000; + description = "Port the OnlyOffice DocumentServer should listens on."; + }; + + examplePort = mkOption { + type = types.port; + default = null; + description = "Port the OnlyOffice Example server should listens on."; + }; + + postgresHost = mkOption { + type = types.str; + default = "/run/postgresql"; + description = "The Postgresql hostname or socket path OnlyOffice should connect to."; + }; + + postgresName = mkOption { + type = types.str; + default = "onlyoffice"; + description = "The name of databse OnlyOffice should user."; + }; + + postgresPasswordFile = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Path to a file that contains the password OnlyOffice should use to connect to Postgresql. + Unused when using socket authentication. + ''; + }; + + postgresUser = mkOption { + type = types.str; + default = "onlyoffice"; + description = '' + The username OnlyOffice should use to connect to Postgresql. + Unused when using socket authentication. + ''; + }; + + rabbitmqUrl = mkOption { + type = types.str; + default = "amqp://guest:guest@localhost:5672"; + description = "The Rabbitmq in amqp URI style OnlyOffice should connect to."; + }; + }; + + config = lib.mkIf cfg.enable { + services = { + nginx = { + enable = mkDefault true; + # misses text/csv, font/ttf, application/x-font-ttf, application/rtf, application/wasm + recommendedGzipSettings = mkDefault true; + recommendedProxySettings = mkDefault true; + + upstreams = { + # /etc/nginx/includes/http-common.conf + onlyoffice-docservice = { + servers = { "localhost:${toString cfg.port}" = { }; }; + }; + onlyoffice-example = lib.mkIf cfg.enableExampleServer { + servers = { "localhost:${toString cfg.examplePort}" = { }; }; + }; + }; + + virtualHosts.${cfg.hostname} = { + locations = { + # /etc/nginx/includes/ds-docservice.conf + "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(web-apps\/apps\/api\/documents\/api\.js)$".extraConfig = '' + expires -1; + alias ${cfg.package}/var/www/onlyoffice/documentserver/$2; + ''; + "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(web-apps)(\/.*\.json)$".extraConfig = '' + expires 365d; + error_log /dev/null crit; + alias ${cfg.package}/var/www/onlyoffice/documentserver/$2$3; + ''; + "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(sdkjs-plugins)(\/.*\.json)$".extraConfig = '' + expires 365d; + error_log /dev/null crit; + alias ${cfg.package}/var/www/onlyoffice/documentserver/$2$3; + ''; + "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(web-apps|sdkjs|sdkjs-plugins|fonts)(\/.*)$".extraConfig = '' + expires 365d; + alias ${cfg.package}/var/www/onlyoffice/documentserver/$2$3; + ''; + "~* ^(\/cache\/files.*)(\/.*)".extraConfig = '' + alias /var/lib/onlyoffice/documentserver/App_Data$1; + add_header Content-Disposition "attachment; filename*=UTF-8''$arg_filename"; + + set $secret_string verysecretstring; + secure_link $arg_md5,$arg_expires; + secure_link_md5 "$secure_link_expires$uri$secret_string"; + + if ($secure_link = "") { + return 403; + } + + if ($secure_link = "0") { + return 410; + } + ''; + "~* ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(internal)(\/.*)$".extraConfig = '' + allow 127.0.0.1; + deny all; + proxy_pass http://onlyoffice-docservice/$2$3; + ''; + "~* ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(info)(\/.*)$".extraConfig = '' + allow 127.0.0.1; + deny all; + proxy_pass http://onlyoffice-docservice/$2$3; + ''; + "/".extraConfig = '' + proxy_pass http://onlyoffice-docservice; + ''; + "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?(\/doc\/.*)".extraConfig = '' + proxy_pass http://onlyoffice-docservice$2; + proxy_http_version 1.1; + ''; + "/${cfg.package.version}/".extraConfig = '' + proxy_pass http://onlyoffice-docservice/; + ''; + "~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\d]+)?\/(dictionaries)(\/.*)$".extraConfig = '' + expires 365d; + alias ${cfg.package}/var/www/onlyoffice/documentserver/$2$3; + ''; + # /etc/nginx/includes/ds-example.conf + "~ ^(\/welcome\/.*)$".extraConfig = '' + expires 365d; + alias ${cfg.package}/var/www/onlyoffice/documentserver-example$1; + index docker.html; + ''; + "/example/".extraConfig = lib.mkIf cfg.enableExampleServer '' + proxy_pass http://onlyoffice-example/; + proxy_set_header X-Forwarded-Path /example; + ''; + }; + extraConfig = '' + rewrite ^/$ /welcome/ redirect; + rewrite ^\/OfficeWeb(\/apps\/.*)$ /${cfg.package.version}/web-apps$1 redirect; + rewrite ^(\/web-apps\/apps\/(?!api\/).*)$ /${cfg.package.version}$1 redirect; + + # based on https://github.com/ONLYOFFICE/document-server-package/blob/master/common/documentserver/nginx/includes/http-common.conf.m4#L29-L34 + # without variable indirection and correct variable names + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + # required for CSP to take effect + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # required for websocket + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + ''; + }; + }; + + rabbitmq.enable = lib.mkDefault true; + + postgresql = { + enable = lib.mkDefault true; + ensureDatabases = [ "onlyoffice" ]; + ensureUsers = [{ + name = "onlyoffice"; + ensurePermissions = { "DATABASE \"onlyoffice\"" = "ALL PRIVILEGES"; }; + }]; + }; + }; + + systemd.services = { + onlyoffice-converter = { + description = "onlyoffice converter"; + after = [ "network.target" "onlyoffice-docservice.service" "postgresql.service" ]; + requires = [ "network.target" "onlyoffice-docservice.service" "postgresql.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${cfg.package.fhs}/bin/onlyoffice-wrapper FileConverter/converter /run/onlyoffice/config"; + Group = "onlyoffice"; + Restart = "always"; + RuntimeDirectory = "onlyoffice"; + StateDirectory = "onlyoffice"; + Type = "simple"; + User = "onlyoffice"; + }; + }; + + onlyoffice-docservice = + let + onlyoffice-prestart = pkgs.writeShellScript "onlyoffice-prestart" '' + PATH=$PATH:${lib.makeBinPath (with pkgs; [ jq moreutils config.services.postgresql.package ])} + umask 077 + mkdir -p /run/onlyoffice/config/ /var/lib/onlyoffice/documentserver/sdkjs/{slide/themes,common}/ /var/lib/onlyoffice/documentserver/{fonts,server/FileConverter/bin}/ + cp -r ${cfg.package}/etc/onlyoffice/documentserver/* /run/onlyoffice/config/ + chmod u+w /run/onlyoffice/config/default.json + + cp /run/onlyoffice/config/default.json{,.orig} + + # for a mapping of environment variables from the docker container to json options see + # https://github.com/ONLYOFFICE/Docker-DocumentServer/blob/master/run-document-server.sh + jq ' + .services.CoAuthoring.server.port = ${toString cfg.port} | + .services.CoAuthoring.sql.dbHost = "${cfg.postgresHost}" | + .services.CoAuthoring.sql.dbName = "${cfg.postgresName}" | + ${lib.optionalString (cfg.postgresPasswordFile != null) '' + .services.CoAuthoring.sql.dbPass = "'"$(cat ${cfg.postgresPasswordFile})"'" | + ''} + .services.CoAuthoring.sql.dbUser = "${cfg.postgresUser}" | + ${lib.optionalString (cfg.jwtSecretFile != null) '' + .services.CoAuthoring.token.enable.browser = true | + .services.CoAuthoring.token.enable.request.inbox = true | + .services.CoAuthoring.token.enable.request.outbox = true | + .services.CoAuthoring.secret.inbox.string = "'"$(cat ${cfg.jwtSecretFile})"'" | + .services.CoAuthoring.secret.outbox.string = "'"$(cat ${cfg.jwtSecretFile})"'" | + .services.CoAuthoring.secret.session.string = "'"$(cat ${cfg.jwtSecretFile})"'" | + ''} + .rabbitmq.url = "${cfg.rabbitmqUrl}" + ' /run/onlyoffice/config/default.json | sponge /run/onlyoffice/config/default.json + + if ! psql -d onlyoffice -c "SELECT 'task_result'::regclass;" >/dev/null; then + psql -f ${cfg.package}/var/www/onlyoffice/documentserver/server/schema/postgresql/createdb.sql + fi + ''; + in + { + description = "onlyoffice documentserver"; + after = [ "network.target" "postgresql.service" ]; + requires = [ "postgresql.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${cfg.package.fhs}/bin/onlyoffice-wrapper DocService/docservice /run/onlyoffice/config"; + ExecStartPre = onlyoffice-prestart; + Group = "onlyoffice"; + Restart = "always"; + RuntimeDirectory = "onlyoffice"; + StateDirectory = "onlyoffice"; + Type = "simple"; + User = "onlyoffice"; + }; + }; + }; + + users.users = { + onlyoffice = { + description = "OnlyOffice Service"; + group = "onlyoffice"; + isSystemUser = true; + }; + }; + + users.groups.onlyoffice = { }; + }; +} diff --git a/pkgs/servers/onlyoffice-documentserver/default.nix b/pkgs/servers/onlyoffice-documentserver/default.nix new file mode 100644 index 000000000000..703eaecf6016 --- /dev/null +++ b/pkgs/servers/onlyoffice-documentserver/default.nix @@ -0,0 +1,152 @@ +{ lib +, stdenv +, buildFHSUserEnvBubblewrap +, corefonts +, dejavu_fonts +, dpkg +, fetchurl +, gcc-unwrapped +, liberation_ttf_v1 +, writeScript +, xorg +}: + +let + # var/www/onlyoffice/documentserver/server/DocService/docservice + onlyoffice-documentserver = stdenv.mkDerivation rec { + pname = "onlyoffice-documentserver"; + version = "7.1.1-23"; + + src = fetchurl { + url = "https://github.com/ONLYOFFICE/DocumentServer/releases/download/v${lib.concatStringsSep "." (lib.take 3 (lib.splitVersion version))}/onlyoffice-documentserver_amd64.deb"; + sha256 = "sha256-hmQx8htSjFszdSAzJgiU7Lo6ebF7TVRfK8rJbJDhX5Q="; + }; + + preferLocalBuild = true; + + unpackCmd = "dpkg -x $curSrc source"; + + nativeBuildInputs = [ + dpkg + ]; + + installPhase = '' + # replace dangling symlinks which are not copied into fhs with actually files + rm lib/*.so* + for file in var/www/onlyoffice/documentserver/server/FileConverter/bin/*.so* ; do + ln -rs "$file" lib/$(basename "$file") + done + + # NixOS uses systemd, not supervisor + rm -rf etc/supervisor + + install -Dm755 usr/bin/documentserver-prepare4shutdown.sh -t $out/bin + # maintainer scripts which expect supervisorctl, try to write into the nix store or are handled by nixos modules + rm -rf usr/bin + + # .deb default documentation + rm -rf usr/share + + # required for bwrap --bind + mkdir -p var/lib/onlyoffice/ var/www/onlyoffice/documentserver/fonts/ + + mv * $out/ + ''; + + # stripping self extracting javascript binaries likely breaks them + dontStrip = true; + + passthru = { + fhs = buildFHSUserEnvBubblewrap { + name = "onlyoffice-wrapper"; + + targetPkgs = pkgs: [ + gcc-unwrapped.lib + onlyoffice-documentserver + + # fonts + corefonts + dejavu_fonts + liberation_ttf_v1 + ]; + + extraBwrapArgs = [ + "--bind var/lib/onlyoffice/ var/lib/onlyoffice/" + "--bind var/lib/onlyoffice/documentserver/sdkjs/common/ var/www/onlyoffice/documentserver/sdkjs/common/" + "--bind var/lib/onlyoffice/documentserver/sdkjs/slide/themes/ var/www/onlyoffice/documentserver/sdkjs/slide/themes/" + "--bind var/lib/onlyoffice/documentserver/fonts/ var/www/onlyoffice/documentserver/fonts/" + "--bind var/lib/onlyoffice/documentserver/server/FileConverter/bin/ var/www/onlyoffice/documentserver/server/FileConverter/bin/" + ]; + + runScript = writeScript "onlyoffice-documentserver-run-script" '' + export NODE_CONFIG_DIR=$2 + export NODE_DISABLE_COLORS=1 + export NODE_ENV=production-linux + + if [[ $1 == DocService/docservice ]]; then + mkdir -p var/www/onlyoffice/documentserver/sdkjs/slide/themes/ + # symlinking themes/src breaks discovery in allfontsgen + rm -rf var/www/onlyoffice/documentserver/sdkjs/slide/themes/src + cp -r ${onlyoffice-documentserver}/var/www/onlyoffice/documentserver/sdkjs/slide/themes/src var/www/onlyoffice/documentserver/sdkjs/slide/themes/ + chmod -R u+w var/www/onlyoffice/documentserver/sdkjs/slide/themes/ + + # onlyoffice places generated files in those directores + rm -rf var/www/onlyoffice/documentserver/sdkjs/common/* + ${xorg.lndir}/bin/lndir -silent ${onlyoffice-documentserver}/var/www/onlyoffice/documentserver/sdkjs/common/ var/www/onlyoffice/documentserver/sdkjs/common/ + rm -rf var/www/onlyoffice/documentserver/server/FileConverter/bin/* + ${xorg.lndir}/bin/lndir -silent ${onlyoffice-documentserver}/var/www/onlyoffice/documentserver/server/FileConverter/bin/ var/www/onlyoffice/documentserver/server/FileConverter/bin/ + + # https://github.com/ONLYOFFICE/document-server-package/blob/master/common/documentserver/bin/documentserver-generate-allfonts.sh.m4 + echo -n Generating AllFonts.js, please wait... + "var/www/onlyoffice/documentserver/server/tools/allfontsgen"\ + --input="${onlyoffice-documentserver}/var/www/onlyoffice/documentserver/core-fonts"\ + --allfonts-web="var/www/onlyoffice/documentserver/sdkjs/common/AllFonts.js"\ + --allfonts="var/www/onlyoffice/documentserver/server/FileConverter/bin/AllFonts.js"\ + --images="var/www/onlyoffice/documentserver/sdkjs/common/Images"\ + --selection="var/www/onlyoffice/documentserver/server/FileConverter/bin/font_selection.bin"\ + --output-web="var/www/onlyoffice/documentserver/fonts"\ + --use-system="true" + echo Done + + echo -n Generating presentation themes, please wait... + "var/www/onlyoffice/documentserver/server/tools/allthemesgen"\ + --converter-dir="var/www/onlyoffice/documentserver/server/FileConverter/bin"\ + --src="var/www/onlyoffice/documentserver/sdkjs/slide/themes"\ + --output="var/www/onlyoffice/documentserver/sdkjs/common/Images" + + "var/www/onlyoffice/documentserver/server/tools/allthemesgen"\ + --converter-dir="var/www/onlyoffice/documentserver/server/FileConverter/bin"\ + --src="var/www/onlyoffice/documentserver/sdkjs/slide/themes"\ + --output="var/www/onlyoffice/documentserver/sdkjs/common/Images"\ + --postfix="ios"\ + --params="280,224" + + "var/www/onlyoffice/documentserver/server/tools/allthemesgen"\ + --converter-dir="var/www/onlyoffice/documentserver/server/FileConverter/bin"\ + --src="var/www/onlyoffice/documentserver/sdkjs/slide/themes"\ + --output="var/www/onlyoffice/documentserver/sdkjs/common/Images"\ + --postfix="android"\ + --params="280,224" + echo Done + fi + + exec var/www/onlyoffice/documentserver/server/$1 + ''; + }; + }; + + meta = with lib; { + description = "ONLYOFFICE Document Server is an online office suite comprising viewers and editors"; + longDescription = '' + ONLYOFFICE Document Server is an online office suite comprising viewers and editors for texts, spreadsheets and presentations, + fully compatible with Office Open XML formats: .docx, .xlsx, .pptx and enabling collaborative editing in real time. + ''; + homepage = "ONLYOFFICE Document Server is an online office suite comprising viewers and editors"; + license = licenses.agpl3; + platforms = [ "x86_64-linux" ]; + sourceProvenance = sourceTypes.binaryNativeCode; + maintainers = with maintainers; [ SuperSandro2000 ]; + }; + }; +in +onlyoffice-documentserver diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index e0ffb80c86d3..480c5ab77043 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -22550,6 +22550,8 @@ with pkgs; oauth2-proxy = callPackage ../servers/oauth2-proxy { }; + onlyoffice-documentserver = callPackage ../servers/onlyoffice-documentserver { }; + openbgpd = callPackage ../servers/openbgpd { }; openafs_1_8 = callPackage ../servers/openafs/1.8 { tsmbac = null; ncurses = null; };