Add PENPOT_INTERNAL_URI to exporter for separate internal and public URI handling (#10630)

Add PENPOT_INTERNAL_URI environment variable to the exporter. This allows
separating the URI used for internal communication (headless browser to
frontend) from the public URI used for resource references in exported SVGs.

Previously, PENPOT_PUBLIC_URI served both purposes, which caused exported
SVGs to contain broken font URLs when the internal Docker address was used.

Changes:
- Add :internal-uri to exporter config schema with fallback to :public-uri
- Add get-internal-uri helper function
- Use internal-uri for browser navigation in SVG/PDF/bitmap renderers
- Post-process SVG output to replace internal URI with public URI
- Use internal-uri for backend API calls in resource handler
- Log both URIs on startup
- Update docker-compose.yaml to use both variables
- Document the new variable in configuration.md

Closes #10627

AI-assisted-by: mimo-v2.5-pro
This commit is contained in:
Andrey Antukh 2026-07-10 10:41:49 +02:00 committed by GitHub
parent ad4dae5f28
commit e73aa9e981
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 45 additions and 7 deletions

View File

@ -197,10 +197,10 @@ services:
- penpot
environment:
<< : [*penpot-secret-key]
<< : [*penpot-secret-key, *penpot-public-uri]
# Don't touch it; this uses an internal docker network to
# communicate with the frontend.
PENPOT_PUBLIC_URI: http://penpot-frontend:8080
PENPOT_INTERNAL_URI: http://penpot-frontend:8080
## Valkey (or previously Redis) is used for the websockets notifications.
PENPOT_REDIS_URI: redis://penpot-valkey/0

View File

@ -651,6 +651,21 @@ PENPOT_EXPORTER_URI: http://your-penpot-exporter:6061
These variables are used for generate correct nginx.conf file on container startup.
### Exporter
The exporter uses this variable:
```bash
# Exporter
PENPOT_INTERNAL_URI: http://penpot-frontend:8080
```
- `PENPOT_INTERNAL_URI`: The URI used by the exporter's headless browser to
communicate with the frontend (internal Docker network). Defaults to
`PENPOT_PUBLIC_URI` if not set. The default value
`http://penpot-frontend:8080` used in the docker-compose is a good default and
it is recommended to keep it unchanged.
## Other flags
There are other flags that are useful for a more customized Penpot experience. This section has the list of the flags meant

View File

@ -22,6 +22,7 @@
(def ^:private defaults
{:public-uri "http://localhost:3449"
:internal-uri nil
:tenant "default"
:host "localhost"
:http-server-port 6061
@ -33,6 +34,7 @@
[:map {:title "config"}
[:secret-key :string]
[:public-uri {:optional true} ::sm/uri]
[:internal-uri {:optional true} ::sm/uri]
[:exporter-shared-key {:optional true} :string]
[:host {:optional true} :string]
[:tenant {:optional true} :string]
@ -100,6 +102,12 @@
([key default]
(c/get config key default)))
(defn get-internal-uri
"Returns internal-uri if set, otherwise falls back to public-uri."
[]
(or (c/get config :internal-uri)
(c/get config :public-uri)))
(def management-key
(let [key (or (c/get config :exporter-shared-key)
(let [secret-key (c/get config :secret-key)

View File

@ -21,6 +21,7 @@
[& _]
(l/info :msg "initializing"
:public-uri (str (cf/get :public-uri))
:internal-uri (str (cf/get-internal-uri))
:version (:full cf/version))
(p/do!
(bwr/init)

View File

@ -79,7 +79,7 @@
:method "POST"
:body fdata
:dispatcher agent}
uri (-> (cf/get :public-uri)
uri (-> (cf/get-internal-uri)
(u/ensure-path-slash)
(u/join "api/management/methods/upload-tempfile")
(str))]

View File

@ -62,7 +62,7 @@
:skip-children skip-children
:wasm (when is-wasm "true")
:scale scale}
uri (-> (cf/get :public-uri)
uri (-> (cf/get-internal-uri)
(u/ensure-path-slash)
(u/join "render.html")
(assoc :query (u/map->query-string params)))]

View File

@ -77,7 +77,7 @@
(on-object (assoc object :path path))
(p/recur (rest objects))))))]
(let [base-uri (-> (cf/get :public-uri)
(let [base-uri (-> (cf/get-internal-uri)
(u/ensure-path-slash))]
(bw/exec! (prepare-options base-uri)
(partial render base-uri)))))

View File

@ -108,6 +108,18 @@
{:width width
:height height}))
(defn- replace-internal-uris
"Replaces internal-uri references with public-uri in SVG output.
This ensures that font URLs and other resource references in the
exported SVG use the public-facing URI accessible to end users."
[svg-content]
(let [internal-uri (str (cf/get-internal-uri))
public-uri (str (cf/get :public-uri))]
(if (and (not= internal-uri public-uri)
(str/includes? svg-content internal-uri))
(str/replace svg-content internal-uri public-uri)
svg-content)))
(defn render
[{:keys [page-id file-id share-id objects token scale type]} on-object]
(letfn [(convert-to-ppm [pngpath]
@ -320,7 +332,9 @@
result (if (contains? cf/flags :exporter-svgo)
(svgo/optimize result svgo/defaultOptions)
result)]
result)
result (replace-internal-uris result)]
;; (println "------- ORIGIN:")
;; (cljs.pprint/pprint (xml->clj xmldata))
@ -349,7 +363,7 @@
:render-embed true
:object-id (mapv :id objects)
:route "objects"}
uri (-> (cf/get :public-uri)
uri (-> (cf/get-internal-uri)
(u/ensure-path-slash)
(u/join "render.html")
(assoc :query (u/map->query-string params)))]