-
-
Notifications
You must be signed in to change notification settings - Fork 13.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7b9a81a
commit a24fa60
Showing
5 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,258 @@ | ||
{ | ||
config, | ||
lib, | ||
pkgs, | ||
... | ||
}: | ||
let | ||
cfg = config.services.gotenberg; | ||
|
||
args = | ||
[ | ||
"--api-port=${toString cfg.port}" | ||
"--api-timeout=${cfg.timeout}" | ||
"--api-root-path=${cfg.rootPath}" | ||
"--log-level=${cfg.logLevel}" | ||
"--chromium-max-queue-size=${toString cfg.chromium.maxQueueSize}" | ||
"--libreoffice-restart-after=${toString cfg.libreoffice.restartAfter}" | ||
"--libreoffice-max-queue-size=${toString cfg.libreoffice.maxQueueSize}" | ||
"--pdfengines-engines=${lib.concatStringsSep "," cfg.pdfEngines}" | ||
] | ||
++ optional cfg.enableBasicAuth "--api-enable-basic-auth" | ||
++ optional cfg.chromium.autoStart "--chromium-auto-start" | ||
++ optional cfg.chromium.disableJavascript "--chromium-disable-javascript" | ||
++ optional cfg.chromium.disableRoutes "--chromium-disable-routes" | ||
++ optional cfg.libreoffice.autoStart "--libreoffice-auto-start" | ||
++ optional cfg.libreoffice.disableRoutes "--libreoffice-disable-routes"; | ||
|
||
inherit (lib) | ||
mkEnableOption | ||
mkPackageOption | ||
mkOption | ||
types | ||
mkIf | ||
optional | ||
optionalAttrs | ||
; | ||
in | ||
{ | ||
options = { | ||
services.gotenberg = { | ||
enable = mkEnableOption "Gotenberg, a stateless API for PDF files"; | ||
|
||
# Users can override only gotenberg, libreoffice and chromium if they want to (eg. ungoogled-chromium, different LO version, etc) | ||
# Don't allow setting the qpdf, pdftk, or unoconv paths, as those are very stable | ||
# and there's only one version of each. | ||
package = mkPackageOption pkgs "gotenberg" { }; | ||
|
||
port = mkOption { | ||
type = types.port; | ||
default = 3000; | ||
description = "Port on which the API should listen."; | ||
}; | ||
|
||
timeout = mkOption { | ||
type = types.nullOr types.str; | ||
default = "30s"; | ||
description = "Timeout for API requests."; | ||
}; | ||
|
||
rootPath = mkOption { | ||
type = types.str; | ||
default = "/"; | ||
description = "Root path for the Gotenberg API."; | ||
}; | ||
|
||
enableBasicAuth = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = '' | ||
HTTP Basic Authentication. | ||
If you set this, be sure to set `GOTENBERG_API_BASIC_AUTH_USERNAME`and `GOTENBERG_API_BASIC_AUTH_PASSWORD` | ||
in your `services.gotenberg.environmentFile` file. | ||
''; | ||
}; | ||
|
||
extraFontPackages = mkOption { | ||
type = types.listOf types.package; | ||
default = [ ]; | ||
description = "Extra fonts to make available."; | ||
}; | ||
|
||
chromium = { | ||
package = mkPackageOption pkgs "chromium" { }; | ||
|
||
maxQueueSize = mkOption { | ||
type = types.int; | ||
default = 0; | ||
description = "Maximum queue size for chromium-based conversions. Setting to 0 disables the limit."; | ||
}; | ||
|
||
autoStart = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = "Automatically start chromium when Gotenberg starts. If false, Chromium will start on the first conversion request that uses it."; | ||
}; | ||
|
||
disableJavascript = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = "Disable Javascript execution."; | ||
}; | ||
|
||
disableRoutes = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = "Disable all routes allowing Chromium-based conversion."; | ||
}; | ||
}; | ||
|
||
libreoffice = { | ||
package = mkPackageOption pkgs "libreoffice" { }; | ||
|
||
restartAfter = mkOption { | ||
type = types.int; | ||
default = 10; | ||
description = "Restart LibreOffice after this many conversions. Setting to 0 disables this feature."; | ||
}; | ||
|
||
maxQueueSize = mkOption { | ||
type = types.int; | ||
default = 0; | ||
description = "Maximum queue size for LibreOffice-based conversions. Setting to 0 disables the limit."; | ||
}; | ||
|
||
autoStart = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = "Automatically start LibreOffice when Gotenberg starts. If false, Chromium will start on the first conversion request that uses it."; | ||
}; | ||
|
||
disableRoutes = mkOption { | ||
type = types.bool; | ||
default = false; | ||
description = "Disable all routes allowing LibreOffice-based conversion."; | ||
}; | ||
}; | ||
|
||
pdfEngines = mkOption { | ||
type = types.listOf ( | ||
types.enum [ | ||
"pdftk" | ||
"qpdf" | ||
"libreoffice-pdfengine" | ||
"exiftool" | ||
"pdfcpu" | ||
] | ||
); | ||
default = [ | ||
"pdftk" | ||
"qpdf" | ||
"libreoffice-pdfengine" | ||
"exiftool" | ||
"pdfcpu" | ||
]; | ||
description = '' | ||
PDF engines to enable. Each one can be used to perform a specific task. | ||
See [the documentation](https://gotenberg.dev/docs/configuration#pdf-engines) for more details. | ||
Defaults to all possible PDF engines. | ||
''; | ||
}; | ||
|
||
logLevel = mkOption { | ||
type = types.enum [ | ||
"error" | ||
"warn" | ||
"info" | ||
"debug" | ||
]; | ||
default = "info"; | ||
description = "The logging level for Gotenberg."; | ||
}; | ||
|
||
environmentFile = mkOption { | ||
type = types.nullOr types.path; | ||
default = null; | ||
description = "Environment file to load extra environment variables from."; | ||
}; | ||
|
||
extraArgs = mkOption { | ||
type = types.listOf types.str; | ||
default = [ ]; | ||
description = "Any extra command-line flags to pass to the Gotenberg service."; | ||
}; | ||
}; | ||
}; | ||
|
||
config = mkIf cfg.enable { | ||
assertions = [ | ||
{ | ||
assertion = cfg.enableBasicAuth -> cfg.environmentFile != null; | ||
message = '' | ||
When enabling HTTP Basic Authentication with `services.gotenberg.enableBasicAuth`, | ||
you must provide an environment file via `services.gotenberg.environmentFile` with the appropriate environment variables set in it. | ||
See `services.gotenberg.enableBasicAuth` for the names of those variables. | ||
''; | ||
} | ||
]; | ||
|
||
systemd.services.gotenberg = { | ||
description = "Gotenberg API server"; | ||
after = [ "network.target" ]; | ||
wantedBy = [ "multi-user.target" ]; | ||
path = [ cfg.package ]; | ||
environment = { | ||
LIBREOFFICE_BIN_PATH = "${cfg.libreoffice.package}/lib/libreoffice/program/soffice.bin"; | ||
CHROMIUM_BIN_PATH = lib.getExe cfg.chromium.package; | ||
FONTCONFIG_FILE = pkgs.makeFontsConf { | ||
fontDirectories = [ pkgs.liberation_ttf_v2 ] ++ cfg.extraFontPackages; | ||
}; | ||
}; | ||
serviceConfig = { | ||
Type = "simple"; | ||
DynamicUser = true; | ||
ExecStart = "${lib.getExe cfg.package} ${lib.escapeShellArgs args}"; | ||
|
||
# Hardening options | ||
PrivateDevices = true; | ||
PrivateIPC = true; | ||
PrivateUsers = true; | ||
|
||
ProtectClock = true; | ||
ProtectControlGroups = true; | ||
ProtectHome = true; | ||
ProtectHostname = true; | ||
ProtectKernelLogs = true; | ||
ProtectKernelModules = true; | ||
ProtectKernelTunables = true; | ||
ProtectProc = "invisible"; | ||
ProcSubset = "pid"; | ||
|
||
RestrictAddressFamilies = [ | ||
"AF_UNIX" | ||
"AF_INET" | ||
"AF_INET6" | ||
"AF_NETLINK" | ||
]; | ||
RestrictNamespaces = true; | ||
RestrictRealtime = true; | ||
|
||
LockPersonality = true; | ||
MemoryDenyWriteExecute = true; | ||
|
||
SystemCallFilter = [ | ||
"@system-service" | ||
"~@resources" | ||
"~@privileged" | ||
]; | ||
SystemCallArchitectures = "native"; | ||
|
||
UMask = 77; | ||
} // optionalAttrs (cfg.environmentFile != null) { EnvironmentFile = cfg.environmentFile; }; | ||
}; | ||
}; | ||
|
||
meta.maintainers = with lib.maintainers; [ pyrox0 ]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import ./make-test-python.nix ( | ||
{ lib, ... }: | ||
|
||
{ | ||
name = "gotenberg"; | ||
meta.maintainers = with lib.maintainers; [ pyrox0 ]; | ||
|
||
nodes.machine = { | ||
services.gotenberg = { | ||
enable = true; | ||
}; | ||
}; | ||
|
||
testScript = '' | ||
start_all() | ||
machine.wait_for_unit("gotenberg.service") | ||
# Gotenberg startup | ||
machine.wait_for_open_port(3000) | ||
# Ensure healthcheck endpoint succeeds | ||
machine.succeed("curl http://localhost:3000/health") | ||
''; | ||
} | ||
) |