From 552da3ca849ed4ee1a0c43c6e55b03f1b7143c21 Mon Sep 17 00:00:00 2001 From: Darko Gjorgjijoski <5760249+gdarko@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:08:24 +0200 Subject: [PATCH] feat(devenv): make the Gotenberg compose stacks work out of the box (#699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Choosing Gotenberg in ./devenv started the `pdf` sidecar and configured nothing else, so the app still defaulted to dompdf. Pointing it at the sidecar by hand then hit the SSRF guard, because `pdf` resolves to a private address on the compose network — the failure #691 fixed, hit from inside our own dev environment. The three gotenberg compose files now set PDF_DRIVER, GOTENBERG_HOST and GOTENBERG_ALLOWED_PRIVATE_HOST on php-fpm, so the stack renders through the sidecar with no .env editing at all. The serversideup pool config already sets `clear_env = no`, so these reach the workers; verified by generating a real invoice PDF end to end (24967 bytes, %PDF-1.4). Setting the environment in compose rather than writing to .env keeps the devenv script from mutating a developer's own file — it does not touch .env today, and the values belong to the compose file the developer selected. Non-Docker setups have the same keys documented in .env.example. devenv now prints what it configured, including that the compose file exempts that one host from the SSRF guard, since a security control being relaxed should not be silent. --- devenv | 6 ++++++ docker/development/docker-compose.mysql.gotenberg.yml | 7 +++++++ docker/development/docker-compose.pgsql.gotenberg.yml | 7 +++++++ docker/development/docker-compose.sqlite.gotenberg.yml | 7 +++++++ 4 files changed, 27 insertions(+) diff --git a/devenv b/devenv index bdb3a46a..3e5018d5 100755 --- a/devenv +++ b/devenv @@ -508,6 +508,12 @@ setup_environment() { if [ "$use_gotenberg" = "yes" ]; then compose_file="docker/development/docker-compose.${db_type}.gotenberg.yml" print_success "Using Gotenberg-enabled compose file" + # The compose file sets PDF_DRIVER, GOTENBERG_HOST and + # GOTENBERG_ALLOWED_PRIVATE_HOST on the php-fpm service, so the sidecar + # works with no .env editing. Say so, because the last one exists to let + # a private host past the SSRF guard and that is worth knowing about. + print_info "PDF driver preconfigured: gotenberg via http://pdf:3000" >&2 + print_info "The compose file exempts that host from the SSRF guard (GOTENBERG_ALLOWED_PRIVATE_HOST)." >&2 else compose_file="docker/development/docker-compose.${db_type}.yml" print_success "Using standard compose file" diff --git a/docker/development/docker-compose.mysql.gotenberg.yml b/docker/development/docker-compose.mysql.gotenberg.yml index ec6712f2..fdef9876 100644 --- a/docker/development/docker-compose.mysql.gotenberg.yml +++ b/docker/development/docker-compose.mysql.gotenberg.yml @@ -8,6 +8,13 @@ services: - UID=${USRID:-1000} - GID=${GRPID:-1000} target: development + environment: + # Gotenberg runs as the `pdf` service below, on this compose network, so + # its host resolves to a private address. PrivateNetworkGuard rejects those + # by default — naming the exact host is what exempts it, and only it. + - PDF_DRIVER=gotenberg + - GOTENBERG_HOST=http://pdf:3000 + - GOTENBERG_ALLOWED_PRIVATE_HOST=http://pdf:3000 volumes: - ../../:/var/www/html networks: diff --git a/docker/development/docker-compose.pgsql.gotenberg.yml b/docker/development/docker-compose.pgsql.gotenberg.yml index 435fbbd9..cf67f3b3 100644 --- a/docker/development/docker-compose.pgsql.gotenberg.yml +++ b/docker/development/docker-compose.pgsql.gotenberg.yml @@ -8,6 +8,13 @@ services: - UID=${USRID:-1000} - GID=${GRPID:-1000} target: development + environment: + # Gotenberg runs as the `pdf` service below, on this compose network, so + # its host resolves to a private address. PrivateNetworkGuard rejects those + # by default — naming the exact host is what exempts it, and only it. + - PDF_DRIVER=gotenberg + - GOTENBERG_HOST=http://pdf:3000 + - GOTENBERG_ALLOWED_PRIVATE_HOST=http://pdf:3000 volumes: - ../../:/var/www/html networks: diff --git a/docker/development/docker-compose.sqlite.gotenberg.yml b/docker/development/docker-compose.sqlite.gotenberg.yml index f612665d..0bc7ae13 100644 --- a/docker/development/docker-compose.sqlite.gotenberg.yml +++ b/docker/development/docker-compose.sqlite.gotenberg.yml @@ -8,6 +8,13 @@ services: - UID=${USRID:-1000} - GID=${GRPID:-1000} target: development + environment: + # Gotenberg runs as the `pdf` service below, on this compose network, so + # its host resolves to a private address. PrivateNetworkGuard rejects those + # by default — naming the exact host is what exempts it, and only it. + - PDF_DRIVER=gotenberg + - GOTENBERG_HOST=http://pdf:3000 + - GOTENBERG_ALLOWED_PRIVATE_HOST=http://pdf:3000 volumes: - ../../:/var/www/html networks: